blob: 81ac7feaf516697aa602a83fef6ffbf634c48376 [file] [log] [blame]
Paul Bakkerc7bb02b2013-09-15 14:54:56 +02001/*
2 * Public Key layer for writing key files and structures
3 *
Paul Bakker7dc4c442014-02-01 22:50:26 +01004 * Copyright (C) 2006-2014, Brainspark B.V.
Paul Bakkerc7bb02b2013-09-15 14:54:56 +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
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020027#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020028#else
29#include POLARSSL_CONFIG_FILE
30#endif
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020031
Paul Bakker4606c732013-09-15 17:04:23 +020032#if defined(POLARSSL_PK_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020033
34#include "polarssl/pk.h"
35#include "polarssl/asn1write.h"
36#include "polarssl/oid.h"
37
38#if defined(POLARSSL_RSA_C)
39#include "polarssl/rsa.h"
40#endif
41#if defined(POLARSSL_ECP_C)
42#include "polarssl/ecp.h"
43#endif
44#if defined(POLARSSL_ECDSA_C)
45#include "polarssl/ecdsa.h"
46#endif
Paul Bakkercff68422013-09-15 20:43:33 +020047#if defined(POLARSSL_PEM_WRITE_C)
Paul Bakker77e23fb2013-09-15 20:03:26 +020048#include "polarssl/pem.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020049#endif
50
Paul Bakker7dc4c442014-02-01 22:50:26 +010051#if defined(POLARSSL_PLATFORM_C)
52#include "polarssl/platform.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020053#else
54#include <stdlib.h>
55#define polarssl_malloc malloc
56#define polarssl_free free
57#endif
58
59#if defined(POLARSSL_RSA_C)
60/*
61 * RSAPublicKey ::= SEQUENCE {
62 * modulus INTEGER, -- n
63 * publicExponent INTEGER -- e
64 * }
65 */
66static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start,
67 rsa_context *rsa )
68{
69 int ret;
70 size_t len = 0;
71
72 ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->E ) );
73 ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->N ) );
74
75 ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
76 ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
77
Paul Bakkerb9cfaa02013-10-11 18:58:55 +020078 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020079}
80#endif /* POLARSSL_RSA_C */
81
82#if defined(POLARSSL_ECP_C)
83/*
84 * EC public key is an EC point
85 */
86static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start,
87 ecp_keypair *ec )
88{
89 int ret;
90 size_t len = 0;
91 unsigned char buf[POLARSSL_ECP_MAX_PT_LEN];
92
93 if( ( ret = ecp_point_write_binary( &ec->grp, &ec->Q,
94 POLARSSL_ECP_PF_UNCOMPRESSED,
95 &len, buf, sizeof( buf ) ) ) != 0 )
96 {
97 return( ret );
98 }
99
100 if( *p - start < (int) len )
101 return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
102
103 *p -= len;
104 memcpy( *p, buf, len );
105
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200106 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200107}
108
109/*
110 * ECParameters ::= CHOICE {
111 * namedCurve OBJECT IDENTIFIER
112 * }
113 */
114static int pk_write_ec_param( unsigned char **p, unsigned char *start,
115 ecp_keypair *ec )
116{
117 int ret;
118 size_t len = 0;
119 const char *oid;
120 size_t oid_len;
121
122 if( ( ret = oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 )
123 return( ret );
124
125 ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
126
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200127 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200128}
129#endif /* POLARSSL_ECP_C */
130
131int pk_write_pubkey( unsigned char **p, unsigned char *start,
132 const pk_context *key )
133{
134 int ret;
135 size_t len = 0;
136
137#if defined(POLARSSL_RSA_C)
138 if( pk_get_type( key ) == POLARSSL_PK_RSA )
139 ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, pk_rsa( *key ) ) );
140 else
141#endif
142#if defined(POLARSSL_ECP_C)
143 if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
144 ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, pk_ec( *key ) ) );
145 else
146#endif
147 return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE );
148
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200149 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200150}
151
152int pk_write_pubkey_der( pk_context *key, unsigned char *buf, size_t size )
153{
154 int ret;
155 unsigned char *c;
156 size_t len = 0, par_len = 0, oid_len;
157 const char *oid;
158
159 c = buf + size;
160
161 ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, key ) );
162
163 if( c - buf < 1 )
164 return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
165
166 /*
167 * SubjectPublicKeyInfo ::= SEQUENCE {
168 * algorithm AlgorithmIdentifier,
169 * subjectPublicKey BIT STRING }
170 */
171 *--c = 0;
172 len += 1;
173
174 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
175 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) );
176
177 if( ( ret = oid_get_oid_by_pk_alg( pk_get_type( key ),
178 &oid, &oid_len ) ) != 0 )
179 {
180 return( ret );
181 }
182
183#if defined(POLARSSL_ECP_C)
184 if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
185 {
186 ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, pk_ec( *key ) ) );
187 }
188#endif
189
190 ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
191 par_len ) );
192
193 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
194 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
195
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200196 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200197}
198
199int pk_write_key_der( pk_context *key, unsigned char *buf, size_t size )
200{
201 int ret;
202 unsigned char *c = buf + size;
203 size_t len = 0;
204
205#if defined(POLARSSL_RSA_C)
206 if( pk_get_type( key ) == POLARSSL_PK_RSA )
207 {
208 rsa_context *rsa = pk_rsa( *key );
209
210 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) );
211 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) );
212 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) );
213 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) );
214 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) );
215 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) );
216 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) );
217 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) );
218 ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) );
219
220 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
221 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
222 }
223 else
Paul Bakker9af723c2014-05-01 13:03:14 +0200224#endif /* POLARSSL_RSA_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200225#if defined(POLARSSL_ECP_C)
226 if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
227 {
228 ecp_keypair *ec = pk_ec( *key );
229 size_t pub_len = 0, par_len = 0;
230
231 /*
232 * RFC 5915, or SEC1 Appendix C.4
233 *
234 * ECPrivateKey ::= SEQUENCE {
235 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
236 * privateKey OCTET STRING,
237 * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
238 * publicKey [1] BIT STRING OPTIONAL
239 * }
240 */
241
242 /* publicKey */
243 ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) );
244
245 if( c - buf < 1 )
246 return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
247 *--c = 0;
248 pub_len += 1;
249
250 ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) );
251 ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) );
252
253 ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) );
254 ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf,
255 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) );
256 len += pub_len;
257
258 /* parameters */
259 ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) );
260
261 ASN1_CHK_ADD( par_len, asn1_write_len( &c, buf, par_len ) );
262 ASN1_CHK_ADD( par_len, asn1_write_tag( &c, buf,
263 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) );
264 len += par_len;
265
266 /* privateKey: write as MPI then fix tag */
267 ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &ec->d ) );
268 *c = ASN1_OCTET_STRING;
269
270 /* version */
271 ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 1 ) );
272
273 ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
274 ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
275 }
276 else
Paul Bakker9af723c2014-05-01 13:03:14 +0200277#endif /* POLARSSL_ECP_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200278 return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE );
279
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200280 return( (int) len );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200281}
282
Paul Bakkercff68422013-09-15 20:43:33 +0200283#if defined(POLARSSL_PEM_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200284
285#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
286#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
287
288#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
289#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
290#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
291#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n"
292
293int pk_write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size )
294{
295 int ret;
296 unsigned char output_buf[4096];
Paul Bakker77e23fb2013-09-15 20:03:26 +0200297 size_t olen = 0;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200298
299 if( ( ret = pk_write_pubkey_der( key, output_buf,
Paul Bakker77e23fb2013-09-15 20:03:26 +0200300 sizeof(output_buf) ) ) < 0 )
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200301 {
302 return( ret );
303 }
304
Paul Bakker77e23fb2013-09-15 20:03:26 +0200305 if( ( ret = pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200306 output_buf + sizeof(output_buf) - ret,
Paul Bakker77e23fb2013-09-15 20:03:26 +0200307 ret, buf, size, &olen ) ) != 0 )
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200308 {
309 return( ret );
310 }
311
312 return( 0 );
313}
314
315int pk_write_key_pem( pk_context *key, unsigned char *buf, size_t size )
316{
317 int ret;
318 unsigned char output_buf[4096];
Paul Bakkerfcc17212013-10-11 09:36:52 +0200319 const char *begin, *end;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200320 size_t olen = 0;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200321
Paul Bakker77e23fb2013-09-15 20:03:26 +0200322 if( ( ret = pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 )
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200323 return( ret );
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200324
325#if defined(POLARSSL_RSA_C)
326 if( pk_get_type( key ) == POLARSSL_PK_RSA )
327 {
328 begin = PEM_BEGIN_PRIVATE_KEY_RSA;
329 end = PEM_END_PRIVATE_KEY_RSA;
330 }
331 else
332#endif
333#if defined(POLARSSL_ECP_C)
334 if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
335 {
336 begin = PEM_BEGIN_PRIVATE_KEY_EC;
337 end = PEM_END_PRIVATE_KEY_EC;
338 }
339 else
340#endif
341 return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE );
342
Paul Bakker77e23fb2013-09-15 20:03:26 +0200343 if( ( ret = pem_write_buffer( begin, end,
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200344 output_buf + sizeof(output_buf) - ret,
Paul Bakker77e23fb2013-09-15 20:03:26 +0200345 ret, buf, size, &olen ) ) != 0 )
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200346 {
347 return( ret );
348 }
349
350 return( 0 );
351}
Paul Bakkercff68422013-09-15 20:43:33 +0200352#endif /* POLARSSL_PEM_WRITE_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200353
Paul Bakker4606c732013-09-15 17:04:23 +0200354#endif /* POLARSSL_PK_WRITE_C */