1 /*
2  *  Certificate request generation
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
21 
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27 
28 #if defined(MBEDTLS_PLATFORM_C)
29 #include "mbedtls/platform.h"
30 #else
31 #include <stdio.h>
32 #define mbedtls_printf     printf
33 #endif
34 
35 #if !defined(MBEDTLS_X509_CSR_WRITE_C) || !defined(MBEDTLS_FS_IO) ||  \
36     !defined(MBEDTLS_PK_PARSE_C) || !defined(MBEDTLS_SHA256_C) || \
37     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
38     !defined(MBEDTLS_PEM_WRITE_C)
main(void)39 int main( void )
40 {
41     mbedtls_printf( "MBEDTLS_X509_CSR_WRITE_C and/or MBEDTLS_FS_IO and/or "
42             "MBEDTLS_PK_PARSE_C and/or MBEDTLS_SHA256_C and/or "
43             "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C "
44             "not defined.\n");
45     return( 0 );
46 }
47 #else
48 
49 #include "mbedtls/x509_csr.h"
50 #include "mbedtls/entropy.h"
51 #include "mbedtls/ctr_drbg.h"
52 #include "mbedtls/error.h"
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #define DFL_FILENAME            "keyfile.key"
59 #define DFL_DEBUG_LEVEL         0
60 #define DFL_OUTPUT_FILENAME     "cert.req"
61 #define DFL_SUBJECT_NAME        "CN=Cert,O=mbed TLS,C=UK"
62 #define DFL_KEY_USAGE           0
63 #define DFL_NS_CERT_TYPE        0
64 
65 #define USAGE \
66     "\n usage: cert_req param=<>...\n"                  \
67     "\n acceptable parameters:\n"                       \
68     "    filename=%%s         default: keyfile.key\n"   \
69     "    debug_level=%%d      default: 0 (disabled)\n"  \
70     "    output_file=%%s      default: cert.req\n"      \
71     "    subject_name=%%s     default: CN=Cert,O=mbed TLS,C=UK\n"   \
72     "    key_usage=%%s        default: (empty)\n"       \
73     "                        Comma-separated-list of values:\n"     \
74     "                          digital_signature\n"     \
75     "                          non_repudiation\n"       \
76     "                          key_encipherment\n"      \
77     "                          data_encipherment\n"     \
78     "                          key_agreement\n"         \
79     "                          key_cert_sign\n"  \
80     "                          crl_sign\n"              \
81     "    ns_cert_type=%%s     default: (empty)\n"       \
82     "                        Comma-separated-list of values:\n"     \
83     "                          ssl_client\n"            \
84     "                          ssl_server\n"            \
85     "                          email\n"                 \
86     "                          object_signing\n"        \
87     "                          ssl_ca\n"                \
88     "                          email_ca\n"              \
89     "                          object_signing_ca\n"     \
90     "\n"
91 
92 /*
93  * global options
94  */
95 struct options
96 {
97     const char *filename;       /* filename of the key file             */
98     int debug_level;            /* level of debugging                   */
99     const char *output_file;    /* where to store the constructed key file  */
100     const char *subject_name;   /* subject name for certificate request */
101     unsigned char key_usage;    /* key usage flags                      */
102     unsigned char ns_cert_type; /* NS cert type                         */
103 } opt;
104 
write_certificate_request(mbedtls_x509write_csr * req,const char * output_file,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)105 int write_certificate_request( mbedtls_x509write_csr *req, const char *output_file,
106                                int (*f_rng)(void *, unsigned char *, size_t),
107                                void *p_rng )
108 {
109     int ret;
110     FILE *f;
111     unsigned char output_buf[4096];
112     size_t len = 0;
113 
114     memset( output_buf, 0, 4096 );
115     if( ( ret = mbedtls_x509write_csr_pem( req, output_buf, 4096, f_rng, p_rng ) ) < 0 )
116         return( ret );
117 
118     len = strlen( (char *) output_buf );
119 
120     if( ( f = fopen( output_file, "w" ) ) == NULL )
121         return( -1 );
122 
123     if( fwrite( output_buf, 1, len, f ) != len )
124     {
125         fclose( f );
126         return( -1 );
127     }
128 
129     fclose( f );
130 
131     return( 0 );
132 }
133 
main(int argc,char * argv[])134 int main( int argc, char *argv[] )
135 {
136     int ret = 0;
137     mbedtls_pk_context key;
138     char buf[1024];
139     int i;
140     char *p, *q, *r;
141     mbedtls_x509write_csr req;
142     mbedtls_entropy_context entropy;
143     mbedtls_ctr_drbg_context ctr_drbg;
144     const char *pers = "csr example app";
145 
146     /*
147      * Set to sane values
148      */
149     mbedtls_x509write_csr_init( &req );
150     mbedtls_x509write_csr_set_md_alg( &req, MBEDTLS_MD_SHA256 );
151     mbedtls_pk_init( &key );
152     mbedtls_ctr_drbg_init( &ctr_drbg );
153     memset( buf, 0, sizeof( buf ) );
154 
155     if( argc == 0 )
156     {
157     usage:
158         mbedtls_printf( USAGE );
159         ret = 1;
160         goto exit;
161     }
162 
163     opt.filename            = DFL_FILENAME;
164     opt.debug_level         = DFL_DEBUG_LEVEL;
165     opt.output_file         = DFL_OUTPUT_FILENAME;
166     opt.subject_name        = DFL_SUBJECT_NAME;
167     opt.key_usage           = DFL_KEY_USAGE;
168     opt.ns_cert_type        = DFL_NS_CERT_TYPE;
169 
170     for( i = 1; i < argc; i++ )
171     {
172 
173         p = argv[i];
174         if( ( q = strchr( p, '=' ) ) == NULL )
175             goto usage;
176         *q++ = '\0';
177 
178         if( strcmp( p, "filename" ) == 0 )
179             opt.filename = q;
180         else if( strcmp( p, "output_file" ) == 0 )
181             opt.output_file = q;
182         else if( strcmp( p, "debug_level" ) == 0 )
183         {
184             opt.debug_level = atoi( q );
185             if( opt.debug_level < 0 || opt.debug_level > 65535 )
186                 goto usage;
187         }
188         else if( strcmp( p, "subject_name" ) == 0 )
189         {
190             opt.subject_name = q;
191         }
192         else if( strcmp( p, "key_usage" ) == 0 )
193         {
194             while( q != NULL )
195             {
196                 if( ( r = strchr( q, ',' ) ) != NULL )
197                     *r++ = '\0';
198 
199                 if( strcmp( q, "digital_signature" ) == 0 )
200                     opt.key_usage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE;
201                 else if( strcmp( q, "non_repudiation" ) == 0 )
202                     opt.key_usage |= MBEDTLS_X509_KU_NON_REPUDIATION;
203                 else if( strcmp( q, "key_encipherment" ) == 0 )
204                     opt.key_usage |= MBEDTLS_X509_KU_KEY_ENCIPHERMENT;
205                 else if( strcmp( q, "data_encipherment" ) == 0 )
206                     opt.key_usage |= MBEDTLS_X509_KU_DATA_ENCIPHERMENT;
207                 else if( strcmp( q, "key_agreement" ) == 0 )
208                     opt.key_usage |= MBEDTLS_X509_KU_KEY_AGREEMENT;
209                 else if( strcmp( q, "key_cert_sign" ) == 0 )
210                     opt.key_usage |= MBEDTLS_X509_KU_KEY_CERT_SIGN;
211                 else if( strcmp( q, "crl_sign" ) == 0 )
212                     opt.key_usage |= MBEDTLS_X509_KU_CRL_SIGN;
213                 else
214                     goto usage;
215 
216                 q = r;
217             }
218         }
219         else if( strcmp( p, "ns_cert_type" ) == 0 )
220         {
221             while( q != NULL )
222             {
223                 if( ( r = strchr( q, ',' ) ) != NULL )
224                     *r++ = '\0';
225 
226                 if( strcmp( q, "ssl_client" ) == 0 )
227                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT;
228                 else if( strcmp( q, "ssl_server" ) == 0 )
229                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER;
230                 else if( strcmp( q, "email" ) == 0 )
231                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL;
232                 else if( strcmp( q, "object_signing" ) == 0 )
233                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING;
234                 else if( strcmp( q, "ssl_ca" ) == 0 )
235                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CA;
236                 else if( strcmp( q, "email_ca" ) == 0 )
237                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA;
238                 else if( strcmp( q, "object_signing_ca" ) == 0 )
239                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA;
240                 else
241                     goto usage;
242 
243                 q = r;
244             }
245         }
246         else
247             goto usage;
248     }
249 
250     if( opt.key_usage )
251         mbedtls_x509write_csr_set_key_usage( &req, opt.key_usage );
252 
253     if( opt.ns_cert_type )
254         mbedtls_x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
255 
256     /*
257      * 0. Seed the PRNG
258      */
259     mbedtls_printf( "  . Seeding the random number generator..." );
260     fflush( stdout );
261 
262     mbedtls_entropy_init( &entropy );
263     if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
264                                (const unsigned char *) pers,
265                                strlen( pers ) ) ) != 0 )
266     {
267         mbedtls_printf( " failed\n  !  mbedtls_ctr_drbg_seed returned %d", ret );
268         goto exit;
269     }
270 
271     mbedtls_printf( " ok\n" );
272 
273     /*
274      * 1.0. Check the subject name for validity
275      */
276     mbedtls_printf( "  . Checking subject name..." );
277     fflush( stdout );
278 
279     if( ( ret = mbedtls_x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
280     {
281         mbedtls_printf( " failed\n  !  mbedtls_x509write_csr_set_subject_name returned %d", ret );
282         goto exit;
283     }
284 
285     mbedtls_printf( " ok\n" );
286 
287     /*
288      * 1.1. Load the key
289      */
290     mbedtls_printf( "  . Loading the private key ..." );
291     fflush( stdout );
292 
293     ret = mbedtls_pk_parse_keyfile( &key, opt.filename, NULL );
294 
295     if( ret != 0 )
296     {
297         mbedtls_printf( " failed\n  !  mbedtls_pk_parse_keyfile returned %d", ret );
298         goto exit;
299     }
300 
301     mbedtls_x509write_csr_set_key( &req, &key );
302 
303     mbedtls_printf( " ok\n" );
304 
305     /*
306      * 1.2. Writing the request
307      */
308     mbedtls_printf( "  . Writing the certificate request ..." );
309     fflush( stdout );
310 
311     if( ( ret = write_certificate_request( &req, opt.output_file,
312                                            mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
313     {
314         mbedtls_printf( " failed\n  !  write_certifcate_request %d", ret );
315         goto exit;
316     }
317 
318     mbedtls_printf( " ok\n" );
319 
320 exit:
321 
322     if( ret != 0 && ret != 1)
323     {
324 #ifdef MBEDTLS_ERROR_C
325         mbedtls_strerror( ret, buf, sizeof( buf ) );
326         mbedtls_printf( " - %s\n", buf );
327 #else
328         mbedtls_printf("\n");
329 #endif
330     }
331 
332     mbedtls_x509write_csr_free( &req );
333     mbedtls_pk_free( &key );
334     mbedtls_ctr_drbg_free( &ctr_drbg );
335     mbedtls_entropy_free( &entropy );
336 
337 #if defined(_WIN32)
338     mbedtls_printf( "  + Press Enter to exit this program.\n" );
339     fflush( stdout ); getchar();
340 #endif
341 
342     return( ret );
343 }
344 #endif /* MBEDTLS_X509_CSR_WRITE_C && MBEDTLS_PK_PARSE_C && MBEDTLS_FS_IO &&
345           MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_PEM_WRITE_C */
346