blob: df7ab64a287575706e7fb45f37d2bac5cc108dbe [file] [log] [blame]
Paul Bakker7c6b2c32013-09-16 13:49:26 +02001/*
2 * X.509 certificate writing
3 *
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +02004 * Copyright (C) 2006-2014, Brainspark B.V.
Paul Bakker7c6b2c32013-09-16 13:49:26 +02005 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25/*
26 * References:
27 * - certificates: RFC 5280, updated by RFC 6818
28 * - CSRs: PKCS#10 v1.7 aka RFC 2986
29 * - attributes: PKCS#9 v2.0 aka RFC 2985
30 */
31
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020032#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020033#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020034#else
35#include POLARSSL_CONFIG_FILE
36#endif
Paul Bakker7c6b2c32013-09-16 13:49:26 +020037
38#if defined(POLARSSL_X509_CRT_WRITE_C)
39
40#include "polarssl/x509_crt.h"
41#include "polarssl/oid.h"
42#include "polarssl/asn1write.h"
43#include "polarssl/sha1.h"
44
45#if defined(POLARSSL_PEM_WRITE_C)
46#include "polarssl/pem.h"
47#endif /* POLARSSL_PEM_WRITE_C */
48
49void x509write_crt_init( x509write_cert *ctx )
50{
51 memset( ctx, 0, sizeof(x509write_cert) );
52
53 mpi_init( &ctx->serial );
54 ctx->version = X509_CRT_VERSION_3;
55}
56
57void x509write_crt_free( x509write_cert *ctx )
58{
59 mpi_free( &ctx->serial );
60
61 asn1_free_named_data_list( &ctx->subject );
62 asn1_free_named_data_list( &ctx->issuer );
63 asn1_free_named_data_list( &ctx->extensions );
64
65 memset( ctx, 0, sizeof(x509write_cert) );
66}
67
Paul Bakker5191e922013-10-11 10:54:28 +020068void x509write_crt_set_version( x509write_cert *ctx, int version )
69{
70 ctx->version = version;
71}
72
Paul Bakker7c6b2c32013-09-16 13:49:26 +020073void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg )
74{
75 ctx->md_alg = md_alg;
76}
77
78void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key )
79{
80 ctx->subject_key = key;
81}
82
83void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key )
84{
85 ctx->issuer_key = key;
86}
87
Paul Bakker50dc8502013-10-28 21:19:10 +010088int x509write_crt_set_subject_name( x509write_cert *ctx,
89 const char *subject_name )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020090{
Paul Bakker86d0c192013-09-18 11:11:02 +020091 return x509_string_to_names( &ctx->subject, subject_name );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020092}
93
Paul Bakker50dc8502013-10-28 21:19:10 +010094int x509write_crt_set_issuer_name( x509write_cert *ctx,
95 const char *issuer_name )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020096{
Paul Bakker86d0c192013-09-18 11:11:02 +020097 return x509_string_to_names( &ctx->issuer, issuer_name );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020098}
99
100int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial )
101{
102 int ret;
103
104 if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 )
105 return( ret );
106
107 return( 0 );
108}
109
Paul Bakker50dc8502013-10-28 21:19:10 +0100110int x509write_crt_set_validity( x509write_cert *ctx, const char *not_before,
111 const char *not_after )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200112{
113 if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 ||
114 strlen(not_after) != X509_RFC5280_UTC_TIME_LEN - 1 )
115 {
Paul Bakker51876562013-09-17 14:36:05 +0200116 return( POLARSSL_ERR_X509_BAD_INPUT_DATA );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200117 }
118 strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN );
119 strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN );
120 ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
121 ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
122
123 return( 0 );
124}
125
126int x509write_crt_set_extension( x509write_cert *ctx,
127 const char *oid, size_t oid_len,
128 int critical,
129 const unsigned char *val, size_t val_len )
130{
131 return x509_set_extension( &ctx->extensions, oid, oid_len,
132 critical, val, val_len );
133}
134
135int x509write_crt_set_basic_constraints( x509write_cert *ctx,
136 int is_ca, int max_pathlen )
137{
138 int ret;
139 unsigned char buf[9];
140 unsigned char *c = buf + sizeof(buf);
141 size_t len = 0;
142
143 memset( buf, 0, sizeof(buf) );
144
145 if( is_ca && max_pathlen > 127 )
Paul Bakker51876562013-09-17 14:36:05 +0200146 return( POLARSSL_ERR_X509_BAD_INPUT_DATA );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200147
148 if( is_ca )
149 {
150 if( max_pathlen >= 0 )
151 {
152 ASN1_CHK_ADD( len, asn1_write_int( &c, buf, max_pathlen ) );
153 }
154 ASN1_CHK_ADD( len, asn1_write_bool( &c, buf, 1 ) );
155 }
156
157 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200158 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED |
159 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200160
161 return x509write_crt_set_extension( ctx, OID_BASIC_CONSTRAINTS,
162 OID_SIZE( OID_BASIC_CONSTRAINTS ),
163 0, buf + sizeof(buf) - len, len );
164}
165
Manuel Pégourié-Gonnard3daaf3d2013-10-27 14:22:02 +0100166#if defined(POLARSSL_SHA1_C)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200167int x509write_crt_set_subject_key_identifier( x509write_cert *ctx )
168{
169 int ret;
170 unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
171 unsigned char *c = buf + sizeof(buf);
172 size_t len = 0;
173
174 memset( buf, 0, sizeof(buf));
175 ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->subject_key ) );
176
177 sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
178 c = buf + sizeof(buf) - 20;
179 len = 20;
180
181 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
182 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_OCTET_STRING ) );
183
184 return x509write_crt_set_extension( ctx, OID_SUBJECT_KEY_IDENTIFIER,
185 OID_SIZE( OID_SUBJECT_KEY_IDENTIFIER ),
186 0, buf + sizeof(buf) - len, len );
187}
188
189int x509write_crt_set_authority_key_identifier( x509write_cert *ctx )
190{
191 int ret;
192 unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
193 unsigned char *c = buf + sizeof(buf);
194 size_t len = 0;
195
196 memset( buf, 0, sizeof(buf));
197 ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->issuer_key ) );
198
199 sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
200 c = buf + sizeof(buf) - 20;
201 len = 20;
202
203 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
204 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONTEXT_SPECIFIC | 0 ) );
205
206 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200207 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED |
208 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200209
210 return x509write_crt_set_extension( ctx, OID_AUTHORITY_KEY_IDENTIFIER,
211 OID_SIZE( OID_AUTHORITY_KEY_IDENTIFIER ),
212 0, buf + sizeof(buf) - len, len );
213}
Manuel Pégourié-Gonnard3daaf3d2013-10-27 14:22:02 +0100214#endif /* POLARSSL_SHA1_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200215
216int x509write_crt_set_key_usage( x509write_cert *ctx, unsigned char key_usage )
217{
218 unsigned char buf[4];
219 unsigned char *c;
220 int ret;
221
222 c = buf + 4;
223
224 if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
225 return( ret );
226
227 ret = x509write_crt_set_extension( ctx, OID_KEY_USAGE,
228 OID_SIZE( OID_KEY_USAGE ),
229 1, buf, 4 );
230 if( ret != 0 )
231 return( ret );
232
233 return( 0 );
234}
235
236int x509write_crt_set_ns_cert_type( x509write_cert *ctx,
237 unsigned char ns_cert_type )
238{
239 unsigned char buf[4];
240 unsigned char *c;
241 int ret;
242
243 c = buf + 4;
244
245 if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
246 return( ret );
247
248 ret = x509write_crt_set_extension( ctx, OID_NS_CERT_TYPE,
249 OID_SIZE( OID_NS_CERT_TYPE ),
250 0, buf, 4 );
251 if( ret != 0 )
252 return( ret );
253
254 return( 0 );
255}
256
257static int x509_write_time( unsigned char **p, unsigned char *start,
258 const char *time, size_t size )
259{
260 int ret;
261 size_t len = 0;
262
263 /*
264 * write ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
265 */
266 if( time[0] == '2' && time[1] == '0' && time [2] < '5' )
267 {
268 ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
269 (const unsigned char *) time + 2,
270 size - 2 ) );
271 ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
272 ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_UTC_TIME ) );
273 }
274 else
275 {
276 ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
277 (const unsigned char *) time,
278 size ) );
279 ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
280 ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) );
281 }
282
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200283 return( (int) len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200284}
285
286int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
287 int (*f_rng)(void *, unsigned char *, size_t),
288 void *p_rng )
289{
290 int ret;
291 const char *sig_oid;
292 size_t sig_oid_len = 0;
293 unsigned char *c, *c2;
294 unsigned char hash[64];
295 unsigned char sig[POLARSSL_MPI_MAX_SIZE];
296 unsigned char tmp_buf[2048];
297 size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
298 size_t len = 0;
299 pk_type_t pk_alg;
300
301 /*
302 * Prepare data to be signed in tmp_buf
303 */
304 c = tmp_buf + sizeof( tmp_buf );
305
306 /* Signature algorithm needed in TBS, and later for actual signature */
307 pk_alg = pk_get_type( ctx->issuer_key );
308 if( pk_alg == POLARSSL_PK_ECKEY )
309 pk_alg = POLARSSL_PK_ECDSA;
310
311 if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
312 &sig_oid, &sig_oid_len ) ) != 0 )
313 {
314 return( ret );
315 }
316
317 /*
318 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
319 */
320 ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
321 ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200322 ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
323 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200324 ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200325 ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC |
326 ASN1_CONSTRUCTED | 3 ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200327
328 /*
329 * SubjectPublicKeyInfo
330 */
331 ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->subject_key,
332 tmp_buf, c - tmp_buf ) );
333 c -= pub_len;
334 len += pub_len;
335
336 /*
337 * Subject ::= Name
338 */
339 ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
340
341 /*
342 * Validity ::= SEQUENCE {
343 * notBefore Time,
344 * notAfter Time }
345 */
346 sub_len = 0;
347
348 ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
349 X509_RFC5280_UTC_TIME_LEN ) );
350
351 ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
352 X509_RFC5280_UTC_TIME_LEN ) );
353
354 len += sub_len;
355 ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200356 ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
357 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200358
359 /*
360 * Issuer ::= Name
361 */
362 ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) );
363
364 /*
365 * Signature ::= AlgorithmIdentifier
366 */
367 ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf,
368 sig_oid, strlen( sig_oid ), 0 ) );
369
370 /*
371 * Serial ::= INTEGER
372 */
373 ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
374
375 /*
376 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
377 */
378 sub_len = 0;
379 ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) );
380 len += sub_len;
381 ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200382 ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC |
383 ASN1_CONSTRUCTED | 0 ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200384
385 ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200386 ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
387 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200388
389 /*
390 * Make signature
391 */
392 md( md_info_from_type( ctx->md_alg ), c, len, hash );
393
394 if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
395 f_rng, p_rng ) ) != 0 )
396 {
397 return( ret );
398 }
399
400 /*
401 * Write data to output buffer
402 */
403 c2 = buf + size;
404 ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
405 sig_oid, sig_oid_len, sig, sig_len ) );
406
407 c2 -= len;
408 memcpy( c2, c, len );
409
410 len += sig_and_oid_len;
411 ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200412 ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED |
413 ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200414
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200415 return( (int) len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200416}
417
418#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
419#define PEM_END_CRT "-----END CERTIFICATE-----\n"
420
421#if defined(POLARSSL_PEM_WRITE_C)
422int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size,
423 int (*f_rng)(void *, unsigned char *, size_t),
424 void *p_rng )
425{
426 int ret;
427 unsigned char output_buf[4096];
428 size_t olen = 0;
429
430 if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf),
431 f_rng, p_rng ) ) < 0 )
432 {
433 return( ret );
434 }
435
436 if( ( ret = pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
437 output_buf + sizeof(output_buf) - ret,
438 ret, buf, size, &olen ) ) != 0 )
439 {
440 return( ret );
441 }
442
443 return( 0 );
444}
445#endif /* POLARSSL_PEM_WRITE_C */
446
447#endif /* POLARSSL_X509_CRT_WRITE_C */