E-MailRelay
gssl_mbedtls_keygen.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gssl_mbedtls_keygen.cpp
19///
20// See:
21// * https://tls.mbed.org/kb/how-to/generate-a-self-signed-certificate
22// * mbedtls/programs/pkey/gen_key.c
23// * mbedtls/programs/x509/cert_write.c
24//
25
26#include "gdef.h"
28#include "gssl_mbedtls_keygen.h"
29#include "gssl_mbedtls_utils.h"
30#include <vector>
31#ifdef G_WINDOWS
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <io.h>
35#else
36#include <fcntl.h>
37#endif
38
39namespace GSsl
40{
41 namespace MbedTlsImp
42 {
43 int open_( const char * path ) ;
44 void close_( int fd ) ;
45 ssize_t read_( int fd , char * p , std::size_t n ) ;
46 void sleep_( int s ) ;
47 void randomFillImp( char * p , std::size_t n ) ;
48 int randomFill( void * , unsigned char * output , std::size_t len , std::size_t * olen ) ;
49 struct FileCloser
50 {
51 explicit FileCloser( int fd ) : m_fd(fd) {}
52 ~FileCloser() { if(m_fd >= 0) close_(m_fd) ; }
53 FileCloser( const FileCloser & ) = delete ;
54 FileCloser( FileCloser && ) = delete ;
55 FileCloser & operator=( const FileCloser & ) = delete ;
56 FileCloser & operator=( FileCloser && ) = delete ;
57 void release() { m_fd = -1 ; }
58 int m_fd ;
59 } ;
60 }
61}
62
63GSsl::MbedTls::Error::Error( const std::string & fname , int rc ) :
64 std::runtime_error( std::string("tls error: ").append(fname).append(": ").append(std::to_string(rc)) )
65{
66}
67
68std::string GSsl::MbedTls::generateKey( const std::string & issuer_name )
69{
70 X<mbedtls_entropy_context> entropy( mbedtls_entropy_init , mbedtls_entropy_free ) ;
71 if( !G::is_windows() )
72 {
73 const int threshold = 32 ;
74 call( FN(mbedtls_entropy_add_source) , entropy.ptr() , MbedTlsImp::randomFill , nullptr ,
75 threshold , MBEDTLS_ENTROPY_SOURCE_STRONG ) ;
76 }
77
78 X<mbedtls_ctr_drbg_context> drbg( mbedtls_ctr_drbg_init , mbedtls_ctr_drbg_free ) ;
79 {
80 std::string seed_name = "gssl_mbedtls" ;
81 auto seed_name_p = reinterpret_cast<const unsigned char*>( seed_name.data() ) ;
82 call( FN(mbedtls_ctr_drbg_seed) , drbg.ptr() , mbedtls_entropy_func , entropy.ptr() , seed_name_p , seed_name.size() ) ;
83 }
84
85 X<mbedtls_pk_context> key( mbedtls_pk_init , mbedtls_pk_free ) ;
86 {
87 const mbedtls_pk_type_t type = MBEDTLS_PK_RSA;
88 const unsigned int keysize = 4096U ;
89 const int exponent = 65537 ;
90 call( FN(mbedtls_pk_setup) , key.ptr() , mbedtls_pk_info_from_type(type) ) ;
91 call( FN(mbedtls_rsa_gen_key) , mbedtls_pk_rsa(key.x) , mbedtls_ctr_drbg_random , drbg.ptr() , keysize , exponent ) ;
92 }
93
94 std::string s_key ;
95 {
96 std::vector<unsigned char> pk_buffer( 16000U ) ;
97 call( FN(mbedtls_pk_write_key_pem) , key.ptr() , &pk_buffer[0] , pk_buffer.size() ) ;
98 pk_buffer[pk_buffer.size()-1] = 0 ;
99 s_key = reinterpret_cast<const char*>( &pk_buffer[0] ) ;
100 }
101
102 // see also mbedtls/programs/x509/cert_write.c ...
103
104 X<mbedtls_mpi> mpi( mbedtls_mpi_init , mbedtls_mpi_free ) ;
105 {
106 const char * serial = "1" ;
107 call( FN(mbedtls_mpi_read_string) , mpi.ptr() , 10 , serial ) ;
108 }
109
110 X<mbedtls_x509write_cert> crt( mbedtls_x509write_crt_init , mbedtls_x509write_crt_free ) ;
111 {
112 const char * not_before = "20200101000000" ;
113 const char * not_after = "20401231235959" ;
114 const int is_ca = 0 ;
115 const int max_pathlen = -1 ;
116 call( FN(mbedtls_x509write_crt_set_subject_key) , crt.ptr() , key.ptr() ) ;
117 call( FN(mbedtls_x509write_crt_set_issuer_key) , crt.ptr() , key.ptr() ) ;
118 call( FN(mbedtls_x509write_crt_set_subject_name) , crt.ptr() , issuer_name.c_str()/*sic*/ ) ;
119 call( FN(mbedtls_x509write_crt_set_issuer_name) , crt.ptr() , issuer_name.c_str() ) ;
120 call( FN(mbedtls_x509write_crt_set_version) , crt.ptr() , MBEDTLS_X509_CRT_VERSION_3 ) ;
121 call( FN(mbedtls_x509write_crt_set_md_alg) , crt.ptr() , MBEDTLS_MD_SHA256 ) ;
122 call( FN(mbedtls_x509write_crt_set_serial) , crt.ptr() , mpi.ptr() ) ;
123 call( FN(mbedtls_x509write_crt_set_validity) , crt.ptr() , not_before , not_after ) ;
124 call( FN(mbedtls_x509write_crt_set_basic_constraints) , crt.ptr() , is_ca , max_pathlen ) ;
125 call( FN(mbedtls_x509write_crt_set_subject_key_identifier) , crt.ptr() ) ;
126 call( FN(mbedtls_x509write_crt_set_authority_key_identifier) , crt.ptr() ) ;
127 }
128
129 std::string s_crt ;
130 {
131 std::vector<unsigned char> crt_buffer( 4096 ) ;
132 call( FN(mbedtls_x509write_crt_pem) , crt.ptr() , &crt_buffer[0] , crt_buffer.size() , mbedtls_ctr_drbg_random , drbg.ptr() ) ;
133 crt_buffer[crt_buffer.size()-1] = 0 ;
134 s_crt = reinterpret_cast<const char*>( &crt_buffer[0] ) ;
135 }
136
137 return s_key.append( s_crt ) ;
138}
139
140void GSsl::MbedTlsImp::randomFillImp( char * p , std::size_t n )
141{
142 // see also mbedtls/programs/pkey/gen_key.c ...
143
144 int fd = open_( "/dev/random" ) ; // not "/dev/urandom" here
145 if( fd < 0 )
146 throw std::runtime_error( "cannot open /dev/random" ) ;
147 FileCloser closer( fd ) ;
148
149 while( n )
150 {
151 ssize_t nread_s = read_( fd , p , n ) ;
152 if( nread_s < 0 )
153 throw std::runtime_error( "cannot read /dev/random" ) ;
154
155 std::size_t nread = static_cast<std::size_t>( nread_s ) ;
156 if( nread > n ) // sanity check
157 throw std::runtime_error( "cannot read /dev/random" ) ;
158
159 n -= nread ;
160 p += nread ;
161
162 if( n )
163 sleep_( 1 ) ; // wait for more entropy -- moot
164 }
165}
166
167int GSsl::MbedTlsImp::randomFill( void * , unsigned char * output , std::size_t len , std::size_t * olen )
168{
169 *olen = 0U ;
170 randomFillImp( reinterpret_cast<char*>(output) , len ) ;
171 *olen = len ;
172 return 0 ;
173}
174
175#ifdef G_WINDOWS
176#pragma warning( suppress : 4996 )
177int GSsl::MbedTlsImp::open_( const char * path ) { return _open( path , _O_RDONLY ) ; }
178void GSsl::MbedTlsImp::close_( int fd ) { _close( fd ) ; }
179ssize_t GSsl::MbedTlsImp::read_( int fd , char * p , std::size_t n ) { return _read( fd , p , static_cast<unsigned>(n) ) ; }
180void GSsl::MbedTlsImp::sleep_( int s ) { Sleep( s * 1000 ) ; }
181#else
182int GSsl::MbedTlsImp::open_( const char * path ) { return ::open( path , O_RDONLY ) ; }
183void GSsl::MbedTlsImp::close_( int fd ) { ::close( fd ) ; }
184ssize_t GSsl::MbedTlsImp::read_( int fd , char * p , std::size_t n ) { return ::read( fd , p , n ) ; }
185void GSsl::MbedTlsImp::sleep_( int s ) { ::sleep( s ) ; }
186#endif
187
TLS/SSL transport layer security classes.
Definition: gssl.h:36
STL namespace.