E-MailRelay
gssl_mbedtls_keygen.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 void release() { m_fd = -1 ; }
53 ~FileCloser() { if(m_fd >= 0) close_(m_fd) ; }
54 int m_fd ;
55 } ;
56 }
57}
58
59GSsl::MbedTls::Error::Error( const std::string & fname , int rc ) :
60 std::runtime_error( std::string("tls error: ").append(fname).append(": ").append(std::to_string(rc)) )
61{
62}
63
64std::string GSsl::MbedTls::generateKey( const std::string & issuer_name )
65{
66 X<mbedtls_entropy_context> entropy( mbedtls_entropy_init , mbedtls_entropy_free ) ;
67 if( !G::is_windows() )
68 {
69 const int threshold = 32 ;
70 call( FN(mbedtls_entropy_add_source) , entropy.ptr() , MbedTlsImp::randomFill , nullptr ,
71 threshold , MBEDTLS_ENTROPY_SOURCE_STRONG ) ;
72 }
73
74 X<mbedtls_ctr_drbg_context> drbg( mbedtls_ctr_drbg_init , mbedtls_ctr_drbg_free ) ;
75 {
76 std::string seed_name = "gssl_mbedtls" ;
77 auto seed_name_p = reinterpret_cast<const unsigned char*>( seed_name.data() ) ;
78 call( FN(mbedtls_ctr_drbg_seed) , drbg.ptr() , mbedtls_entropy_func , entropy.ptr() , seed_name_p , seed_name.size() ) ;
79 }
80
81 X<mbedtls_pk_context> key( mbedtls_pk_init , mbedtls_pk_free ) ;
82 {
83 const mbedtls_pk_type_t type = MBEDTLS_PK_RSA;
84 const unsigned int keysize = 4096U ;
85 const int exponent = 65537 ;
86 call( FN(mbedtls_pk_setup) , key.ptr() , mbedtls_pk_info_from_type(type) ) ;
87 call( FN(mbedtls_rsa_gen_key) , mbedtls_pk_rsa(key.x) , mbedtls_ctr_drbg_random , drbg.ptr() , keysize , exponent ) ;
88 }
89
90 std::string s_key ;
91 {
92 std::vector<unsigned char> pk_buffer( 16000U ) ;
93 call( FN(mbedtls_pk_write_key_pem) , key.ptr() , &pk_buffer[0] , pk_buffer.size() ) ;
94 pk_buffer[pk_buffer.size()-1] = 0 ;
95 s_key = reinterpret_cast<const char*>( &pk_buffer[0] ) ;
96 }
97
98 // see also mbedtls/programs/x509/cert_write.c ...
99
100 X<mbedtls_mpi> mpi( mbedtls_mpi_init , mbedtls_mpi_free ) ;
101 {
102 const char * serial = "1" ;
103 call( FN(mbedtls_mpi_read_string) , mpi.ptr() , 10 , serial ) ;
104 }
105
106 X<mbedtls_x509write_cert> crt( mbedtls_x509write_crt_init , mbedtls_x509write_crt_free ) ;
107 {
108 const char * not_before = "20200101000000" ;
109 const char * not_after = "20401231235959" ;
110 const int is_ca = 0 ;
111 const int max_pathlen = -1 ;
112 call( FN(mbedtls_x509write_crt_set_subject_key) , crt.ptr() , key.ptr() ) ;
113 call( FN(mbedtls_x509write_crt_set_issuer_key) , crt.ptr() , key.ptr() ) ;
114 call( FN(mbedtls_x509write_crt_set_subject_name) , crt.ptr() , issuer_name.c_str()/*sic*/ ) ;
115 call( FN(mbedtls_x509write_crt_set_issuer_name) , crt.ptr() , issuer_name.c_str() ) ;
116 call( FN(mbedtls_x509write_crt_set_version) , crt.ptr() , MBEDTLS_X509_CRT_VERSION_3 ) ;
117 call( FN(mbedtls_x509write_crt_set_md_alg) , crt.ptr() , MBEDTLS_MD_SHA256 ) ;
118 call( FN(mbedtls_x509write_crt_set_serial) , crt.ptr() , mpi.ptr() ) ;
119 call( FN(mbedtls_x509write_crt_set_validity) , crt.ptr() , not_before , not_after ) ;
120 call( FN(mbedtls_x509write_crt_set_basic_constraints) , crt.ptr() , is_ca , max_pathlen ) ;
121 call( FN(mbedtls_x509write_crt_set_subject_key_identifier) , crt.ptr() ) ;
122 call( FN(mbedtls_x509write_crt_set_authority_key_identifier) , crt.ptr() ) ;
123 }
124
125 std::string s_crt ;
126 {
127 std::vector<unsigned char> crt_buffer( 4096 ) ;
128 call( FN(mbedtls_x509write_crt_pem) , crt.ptr() , &crt_buffer[0] , crt_buffer.size() , mbedtls_ctr_drbg_random , drbg.ptr() ) ;
129 crt_buffer[crt_buffer.size()-1] = 0 ;
130 s_crt = reinterpret_cast<const char*>( &crt_buffer[0] ) ;
131 }
132
133 return s_key.append( s_crt ) ;
134}
135
136void GSsl::MbedTlsImp::randomFillImp( char * p , std::size_t n )
137{
138 // see also mbedtls/programs/pkey/gen_key.c ...
139
140 int fd = open_( "/dev/random" ) ; // not "/dev/urandom" here
141 if( fd < 0 )
142 throw std::runtime_error( "cannot open /dev/random" ) ;
143 FileCloser closer( fd ) ;
144
145 while( n )
146 {
147 ssize_t nread_s = read_( fd , p , n ) ;
148 if( nread_s < 0 )
149 throw std::runtime_error( "cannot read /dev/random" ) ;
150
151 std::size_t nread = static_cast<std::size_t>( nread_s ) ;
152 if( nread > n ) // sanity check
153 throw std::runtime_error( "cannot read /dev/random" ) ;
154
155 n -= nread ;
156 p += nread ;
157
158 if( n )
159 sleep_( 1 ) ; // wait for more entropy -- moot
160 }
161}
162
163int GSsl::MbedTlsImp::randomFill( void * , unsigned char * output , std::size_t len , std::size_t * olen )
164{
165 *olen = 0U ;
166 randomFillImp( reinterpret_cast<char*>(output) , len ) ;
167 *olen = len ;
168 return 0 ;
169}
170
171#ifdef G_WINDOWS
172#pragma warning( suppress : 4996 )
173int GSsl::MbedTlsImp::open_( const char * path ) { return _open( path , _O_RDONLY ) ; }
174void GSsl::MbedTlsImp::close_( int fd ) { _close( fd ) ; }
175ssize_t GSsl::MbedTlsImp::read_( int fd , char * p , std::size_t n ) { return _read( fd , p , static_cast<unsigned>(n) ) ; }
176void GSsl::MbedTlsImp::sleep_( int s ) { Sleep( s * 1000 ) ; }
177#else
178int GSsl::MbedTlsImp::open_( const char * path ) { return ::open( path , O_RDONLY ) ; }
179void GSsl::MbedTlsImp::close_( int fd ) { ::close( fd ) ; }
180ssize_t GSsl::MbedTlsImp::read_( int fd , char * p , std::size_t n ) { return ::read( fd , p , n ) ; }
181void GSsl::MbedTlsImp::sleep_( int s ) { ::sleep( s ) ; }
182#endif
183
TLS/SSL transport layer security classes.
Definition: gssl.h:36
STL namespace.