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 #include <stdlib.h>
33 #define mbedtls_printf          printf
34 #define mbedtls_exit            exit
35 #define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
36 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
37 #endif /* MBEDTLS_PLATFORM_C */
38 
39 #if !defined(MBEDTLS_X509_CSR_WRITE_C) || !defined(MBEDTLS_FS_IO) ||  \
40     !defined(MBEDTLS_PK_PARSE_C) || !defined(MBEDTLS_SHA256_C) || \
41     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
42     !defined(MBEDTLS_PEM_WRITE_C)
main(void)43 int main( void )
44 {
45     mbedtls_printf( "MBEDTLS_X509_CSR_WRITE_C and/or MBEDTLS_FS_IO and/or "
46             "MBEDTLS_PK_PARSE_C and/or MBEDTLS_SHA256_C and/or "
47             "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C "
48             "not defined.\n");
49     return( 0 );
50 }
51 #else
52 
53 #include "mbedtls/x509_csr.h"
54 #include "mbedtls/entropy.h"
55 #include "mbedtls/ctr_drbg.h"
56 #include "mbedtls/error.h"
57 
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 
62 #define DFL_FILENAME            "keyfile.key"
63 #define DFL_PASSWORD            NULL
64 #define DFL_DEBUG_LEVEL         0
65 #define DFL_OUTPUT_FILENAME     "cert.req"
66 #define DFL_SUBJECT_NAME        "CN=Cert,O=mbed TLS,C=UK"
67 #define DFL_KEY_USAGE           0
68 #define DFL_NS_CERT_TYPE        0
69 #define DFL_MD_ALG              MBEDTLS_MD_SHA256
70 
71 #define USAGE \
72     "\n usage: cert_req param=<>...\n"                  \
73     "\n acceptable parameters:\n"                       \
74     "    filename=%%s         default: keyfile.key\n"   \
75     "    password=%%s         default: NULL\n"          \
76     "    debug_level=%%d      default: 0 (disabled)\n"  \
77     "    output_file=%%s      default: cert.req\n"      \
78     "    subject_name=%%s     default: CN=Cert,O=mbed TLS,C=UK\n"   \
79     "    key_usage=%%s        default: (empty)\n"       \
80     "                        Comma-separated-list of values:\n"     \
81     "                          digital_signature\n"     \
82     "                          non_repudiation\n"       \
83     "                          key_encipherment\n"      \
84     "                          data_encipherment\n"     \
85     "                          key_agreement\n"         \
86     "                          key_cert_sign\n"  \
87     "                          crl_sign\n"              \
88     "    ns_cert_type=%%s     default: (empty)\n"       \
89     "                        Comma-separated-list of values:\n"     \
90     "                          ssl_client\n"            \
91     "                          ssl_server\n"            \
92     "                          email\n"                 \
93     "                          object_signing\n"        \
94     "                          ssl_ca\n"                \
95     "                          email_ca\n"              \
96     "                          object_signing_ca\n"     \
97     "    md=%%s               default: SHA256\n"       \
98     "                          possible values:\n"     \
99     "                          MD4, MD5, SHA1\n"       \
100     "                          SHA224, SHA256\n"       \
101     "                          SHA384, SHA512\n"       \
102     "\n"
103 
104 #if defined(MBEDTLS_CHECK_PARAMS)
mbedtls_param_failed(const char * failure_condition,const char * file,int line)105 void mbedtls_param_failed( const char *failure_condition,
106                            const char *file,
107                            int line )
108 {
109     mbedtls_printf( "%s:%i: Input param failed - %s\n",
110                     file, line, failure_condition );
111     mbedtls_exit( MBEDTLS_EXIT_FAILURE );
112 }
113 #endif
114 
115 /*
116  * global options
117  */
118 struct options
119 {
120     const char *filename;       /* filename of the key file             */
121     const char *password;       /* password for the key file            */
122     int debug_level;            /* level of debugging                   */
123     const char *output_file;    /* where to store the constructed key file  */
124     const char *subject_name;   /* subject name for certificate request */
125     unsigned char key_usage;    /* key usage flags                      */
126     unsigned char ns_cert_type; /* NS cert type                         */
127     mbedtls_md_type_t md_alg;   /* Hash algorithm used for signature.   */
128 } opt;
129 
write_certificate_request(mbedtls_x509write_csr * req,const char * output_file,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)130 int write_certificate_request( mbedtls_x509write_csr *req, const char *output_file,
131                                int (*f_rng)(void *, unsigned char *, size_t),
132                                void *p_rng )
133 {
134     int ret;
135     FILE *f;
136     unsigned char output_buf[4096];
137     size_t len = 0;
138 
139     memset( output_buf, 0, 4096 );
140     if( ( ret = mbedtls_x509write_csr_pem( req, output_buf, 4096, f_rng, p_rng ) ) < 0 )
141         return( ret );
142 
143     len = strlen( (char *) output_buf );
144 
145     if( ( f = fopen( output_file, "w" ) ) == NULL )
146         return( -1 );
147 
148     if( fwrite( output_buf, 1, len, f ) != len )
149     {
150         fclose( f );
151         return( -1 );
152     }
153 
154     fclose( f );
155 
156     return( 0 );
157 }
158 
main(int argc,char * argv[])159 int main( int argc, char *argv[] )
160 {
161     int ret = 1;
162     int exit_code = MBEDTLS_EXIT_FAILURE;
163     mbedtls_pk_context key;
164     char buf[1024];
165     int i;
166     char *p, *q, *r;
167     mbedtls_x509write_csr req;
168     mbedtls_entropy_context entropy;
169     mbedtls_ctr_drbg_context ctr_drbg;
170     const char *pers = "csr example app";
171 
172     /*
173      * Set to sane values
174      */
175     mbedtls_x509write_csr_init( &req );
176     mbedtls_pk_init( &key );
177     mbedtls_ctr_drbg_init( &ctr_drbg );
178     memset( buf, 0, sizeof( buf ) );
179 
180     if( argc == 0 )
181     {
182     usage:
183         mbedtls_printf( USAGE );
184         goto exit;
185     }
186 
187     opt.filename            = DFL_FILENAME;
188     opt.password            = DFL_PASSWORD;
189     opt.debug_level         = DFL_DEBUG_LEVEL;
190     opt.output_file         = DFL_OUTPUT_FILENAME;
191     opt.subject_name        = DFL_SUBJECT_NAME;
192     opt.key_usage           = DFL_KEY_USAGE;
193     opt.ns_cert_type        = DFL_NS_CERT_TYPE;
194     opt.md_alg              = DFL_MD_ALG;
195 
196     for( i = 1; i < argc; i++ )
197     {
198 
199         p = argv[i];
200         if( ( q = strchr( p, '=' ) ) == NULL )
201             goto usage;
202         *q++ = '\0';
203 
204         if( strcmp( p, "filename" ) == 0 )
205             opt.filename = q;
206         else if( strcmp( p, "password" ) == 0 )
207             opt.password = q;
208         else if( strcmp( p, "output_file" ) == 0 )
209             opt.output_file = q;
210         else if( strcmp( p, "debug_level" ) == 0 )
211         {
212             opt.debug_level = atoi( q );
213             if( opt.debug_level < 0 || opt.debug_level > 65535 )
214                 goto usage;
215         }
216         else if( strcmp( p, "subject_name" ) == 0 )
217         {
218             opt.subject_name = q;
219         }
220         else if( strcmp( p, "md" ) == 0 )
221         {
222             if( strcmp( q, "SHA256" ) == 0 )
223             {
224                 opt.md_alg = MBEDTLS_MD_SHA256;
225             }
226             else if( strcmp( q, "SHA224" ) == 0 )
227             {
228                 opt.md_alg = MBEDTLS_MD_SHA224;
229             }
230             else
231 #if defined(MBEDTLS_MD5_C)
232             if( strcmp( q, "MD5" ) == 0 )
233             {
234                 opt.md_alg = MBEDTLS_MD_MD5;
235             }
236             else
237 #endif /* MBEDTLS_MD5_C */
238 #if defined(MBEDTLS_MD4_C)
239             if( strcmp( q, "MD4" ) == 0 )
240             {
241                 opt.md_alg = MBEDTLS_MD_MD4;
242             }
243             else
244 #endif /* MBEDTLS_MD5_C */
245 #if defined(MBEDTLS_SHA1_C)
246             if( strcmp( q, "SHA1" ) == 0 )
247             {
248                 opt.md_alg = MBEDTLS_MD_SHA1;
249             }
250             else
251 #endif /* MBEDTLS_SHA1_C */
252 #if defined(MBEDTLS_SHA512_C)
253             if( strcmp( q, "SHA384" ) == 0 )
254             {
255                 opt.md_alg = MBEDTLS_MD_SHA384;
256             }
257             else
258             if( strcmp( q, "SHA512" ) == 0 )
259             {
260                 opt.md_alg = MBEDTLS_MD_SHA512;
261             }
262             else
263 #endif /* MBEDTLS_SHA512_C */
264             {
265                 goto usage;
266             }
267         }
268         else if( strcmp( p, "key_usage" ) == 0 )
269         {
270             while( q != NULL )
271             {
272                 if( ( r = strchr( q, ',' ) ) != NULL )
273                     *r++ = '\0';
274 
275                 if( strcmp( q, "digital_signature" ) == 0 )
276                     opt.key_usage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE;
277                 else if( strcmp( q, "non_repudiation" ) == 0 )
278                     opt.key_usage |= MBEDTLS_X509_KU_NON_REPUDIATION;
279                 else if( strcmp( q, "key_encipherment" ) == 0 )
280                     opt.key_usage |= MBEDTLS_X509_KU_KEY_ENCIPHERMENT;
281                 else if( strcmp( q, "data_encipherment" ) == 0 )
282                     opt.key_usage |= MBEDTLS_X509_KU_DATA_ENCIPHERMENT;
283                 else if( strcmp( q, "key_agreement" ) == 0 )
284                     opt.key_usage |= MBEDTLS_X509_KU_KEY_AGREEMENT;
285                 else if( strcmp( q, "key_cert_sign" ) == 0 )
286                     opt.key_usage |= MBEDTLS_X509_KU_KEY_CERT_SIGN;
287                 else if( strcmp( q, "crl_sign" ) == 0 )
288                     opt.key_usage |= MBEDTLS_X509_KU_CRL_SIGN;
289                 else
290                     goto usage;
291 
292                 q = r;
293             }
294         }
295         else if( strcmp( p, "ns_cert_type" ) == 0 )
296         {
297             while( q != NULL )
298             {
299                 if( ( r = strchr( q, ',' ) ) != NULL )
300                     *r++ = '\0';
301 
302                 if( strcmp( q, "ssl_client" ) == 0 )
303                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT;
304                 else if( strcmp( q, "ssl_server" ) == 0 )
305                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER;
306                 else if( strcmp( q, "email" ) == 0 )
307                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL;
308                 else if( strcmp( q, "object_signing" ) == 0 )
309                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING;
310                 else if( strcmp( q, "ssl_ca" ) == 0 )
311                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CA;
312                 else if( strcmp( q, "email_ca" ) == 0 )
313                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA;
314                 else if( strcmp( q, "object_signing_ca" ) == 0 )
315                     opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA;
316                 else
317                     goto usage;
318 
319                 q = r;
320             }
321         }
322         else
323             goto usage;
324     }
325 
326     mbedtls_x509write_csr_set_md_alg( &req, opt.md_alg );
327 
328     if( opt.key_usage )
329         mbedtls_x509write_csr_set_key_usage( &req, opt.key_usage );
330 
331     if( opt.ns_cert_type )
332         mbedtls_x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
333 
334     /*
335      * 0. Seed the PRNG
336      */
337     mbedtls_printf( "  . Seeding the random number generator..." );
338     fflush( stdout );
339 
340     mbedtls_entropy_init( &entropy );
341     if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
342                                (const unsigned char *) pers,
343                                strlen( pers ) ) ) != 0 )
344     {
345         mbedtls_printf( " failed\n  !  mbedtls_ctr_drbg_seed returned %d", ret );
346         goto exit;
347     }
348 
349     mbedtls_printf( " ok\n" );
350 
351     /*
352      * 1.0. Check the subject name for validity
353      */
354     mbedtls_printf( "  . Checking subject name..." );
355     fflush( stdout );
356 
357     if( ( ret = mbedtls_x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
358     {
359         mbedtls_printf( " failed\n  !  mbedtls_x509write_csr_set_subject_name returned %d", ret );
360         goto exit;
361     }
362 
363     mbedtls_printf( " ok\n" );
364 
365     /*
366      * 1.1. Load the key
367      */
368     mbedtls_printf( "  . Loading the private key ..." );
369     fflush( stdout );
370 
371     ret = mbedtls_pk_parse_keyfile( &key, opt.filename, opt.password );
372 
373     if( ret != 0 )
374     {
375         mbedtls_printf( " failed\n  !  mbedtls_pk_parse_keyfile returned %d", ret );
376         goto exit;
377     }
378 
379     mbedtls_x509write_csr_set_key( &req, &key );
380 
381     mbedtls_printf( " ok\n" );
382 
383     /*
384      * 1.2. Writing the request
385      */
386     mbedtls_printf( "  . Writing the certificate request ..." );
387     fflush( stdout );
388 
389     if( ( ret = write_certificate_request( &req, opt.output_file,
390                                            mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
391     {
392         mbedtls_printf( " failed\n  !  write_certifcate_request %d", ret );
393         goto exit;
394     }
395 
396     mbedtls_printf( " ok\n" );
397 
398     exit_code = MBEDTLS_EXIT_SUCCESS;
399 
400 exit:
401 
402     if( exit_code != MBEDTLS_EXIT_SUCCESS )
403     {
404 #ifdef MBEDTLS_ERROR_C
405         mbedtls_strerror( ret, buf, sizeof( buf ) );
406         mbedtls_printf( " - %s\n", buf );
407 #else
408         mbedtls_printf("\n");
409 #endif
410     }
411 
412     mbedtls_x509write_csr_free( &req );
413     mbedtls_pk_free( &key );
414     mbedtls_ctr_drbg_free( &ctr_drbg );
415     mbedtls_entropy_free( &entropy );
416 
417 #if defined(_WIN32)
418     mbedtls_printf( "  + Press Enter to exit this program.\n" );
419     fflush( stdout ); getchar();
420 #endif
421 
422     return( exit_code );
423 }
424 #endif /* MBEDTLS_X509_CSR_WRITE_C && MBEDTLS_PK_PARSE_C && MBEDTLS_FS_IO &&
425           MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_PEM_WRITE_C */
426