some cleanups here and there
[strongswan.git] / src / libstrongswan / crypto / rsa / rsa_public_key.c
1 /**
2 * @file rsa_public_key.c
3 *
4 * @brief Implementation of rsa_public_key_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <gmp.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "rsa_public_key.h"
31
32 #include <crypto/hashers/hasher.h>
33 #include <asn1/asn1.h>
34 #include <asn1/pem.h>
35
36 /*
37 * For simplicity, we use these predefined values for hash algorithm OIDs
38 * These also contain the length of the appended hash
39 * These values are also used in rsa_private_key.c.
40 */
41
42 const u_int8_t md2_oid[] = {
43 0x30,0x20,
44 0x30,0x0c,
45 0x06,0x08,
46 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,
47 0x05,0x00,
48 0x04,0x10
49 };
50
51 const u_int8_t md5_oid[] = {
52 0x30,0x20,
53 0x30,0x0c,
54 0x06,0x08,
55 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,
56 0x05,0x00,
57 0x04,0x10
58 };
59
60 const u_int8_t sha1_oid[] = {
61 0x30,0x21,
62 0x30,0x09,
63 0x06,0x05,
64 0x2b,0x0e,0x03,0x02,0x1a,
65 0x05,0x00,
66 0x04,0x14
67 };
68
69 const u_int8_t sha256_oid[] = {
70 0x30,0x31,
71 0x30,0x0d,
72 0x06,0x09,
73 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,
74 0x05,0x00,
75 0x04,0x20
76 };
77
78 const u_int8_t sha384_oid[] = {
79 0x30,0x41,
80 0x30,0x0d,
81 0x06,0x09,
82 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,
83 0x05,0x00,
84 0x04,0x30
85 };
86
87 const u_int8_t sha512_oid[] = {
88 0x30,0x51,
89 0x30,0x0d,
90 0x06,0x09,
91 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,
92 0x05,0x00,
93 0x04,0x40
94 };
95
96 #define LARGEST_HASH_OID_SIZE sizeof(sha512_oid)
97
98 /* ASN.1 definition public key */
99 static const asn1Object_t pubkey_objects[] = {
100 { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
101 { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */
102 { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */
103 };
104
105 #define PUB_KEY_RSA_PUBLIC_KEY 0
106 #define PUB_KEY_MODULUS 1
107 #define PUB_KEY_EXPONENT 2
108 #define PUB_KEY_ROOF 3
109
110 typedef struct private_rsa_public_key_t private_rsa_public_key_t;
111
112 /**
113 * Private data structure with signing context.
114 */
115 struct private_rsa_public_key_t {
116 /**
117 * Public interface for this signer.
118 */
119 rsa_public_key_t public;
120
121 /**
122 * Public modulus.
123 */
124 mpz_t n;
125
126 /**
127 * Public exponent.
128 */
129 mpz_t e;
130
131 /**
132 * Keysize in bytes.
133 */
134 size_t k;
135
136 /**
137 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
138 */
139 chunk_t keyid;
140
141 /**
142 * @brief Implements the RSAEP algorithm specified in PKCS#1.
143 *
144 * @param this calling object
145 * @param data data to process
146 * @return processed data
147 */
148 chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data);
149
150 /**
151 * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
152 *
153 * @param this calling object
154 * @param data data to process
155 * @return processed data
156 */
157 chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data);
158 };
159
160 private_rsa_public_key_t *rsa_public_key_create_empty(void);
161
162 /**
163 * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
164 */
165 static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
166 {
167 mpz_t m, c;
168 chunk_t encrypted;
169
170 mpz_init(c);
171 mpz_init(m);
172
173 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
174
175 mpz_powm(c, m, this->e, this->n);
176
177 encrypted.len = this->k;
178 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
179
180 mpz_clear(c);
181 mpz_clear(m);
182
183 return encrypted;
184 }
185
186 /**
187 * Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
188 */
189 static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
190 {
191 hasher_t *hasher = NULL;
192 chunk_t hash;
193 chunk_t em;
194 u_int8_t *pos;
195 status_t res = FAILED;
196
197 /* remove any preceding 0-bytes from signature */
198 while (signature.len && *(signature.ptr) == 0x00)
199 {
200 signature.len -= 1;
201 signature.ptr++;
202 }
203
204 if (signature.len > this->k)
205 {
206 return INVALID_ARG;
207 }
208
209 /* unpack signature */
210 em = this->rsavp1(this, signature);
211
212 /* result should look like this:
213 * EM = 0x00 || 0x01 || PS || 0x00 || T.
214 * PS = 0xFF padding, with length to fill em
215 * T = oid || hash
216 */
217
218 /* check magic bytes */
219 if ((*(em.ptr) != 0x00) || (*(em.ptr+1) != 0x01))
220 {
221 goto end;
222 }
223
224 /* find magic 0x00 */
225 pos = em.ptr + 2;
226 while (pos <= em.ptr + em.len)
227 {
228 if (*pos == 0x00)
229 {
230 /* found magic byte, stop */
231 pos++;
232 break;
233 }
234 else if (*pos != 0xFF)
235 {
236 /* bad padding, decryption failed ?!*/
237 goto end;
238 }
239 pos++;
240 }
241
242 if (pos + LARGEST_HASH_OID_SIZE > em.ptr + em.len)
243 {
244 /* not enought room for oid compare */
245 goto end;
246 }
247
248 if (memeq(md2_oid, pos, sizeof(md2_oid)))
249 {
250 hasher = hasher_create(HASH_MD2);
251 pos += sizeof(md2_oid);
252 }
253 else if (memeq(md5_oid, pos, sizeof(md5_oid)))
254 {
255 hasher = hasher_create(HASH_MD5);
256 pos += sizeof(md5_oid);
257 }
258 else if (memeq(sha1_oid, pos, sizeof(sha1_oid)))
259 {
260 hasher = hasher_create(HASH_SHA1);
261 pos += sizeof(sha1_oid);
262 }
263 else if (memeq(sha256_oid, pos, sizeof(sha256_oid)))
264 {
265 hasher = hasher_create(HASH_SHA256);
266 pos += sizeof(sha256_oid);
267 }
268 else if (memeq(sha384_oid, pos, sizeof(sha384_oid)))
269 {
270 hasher = hasher_create(HASH_SHA384);
271 pos += sizeof(sha384_oid);
272 }
273 else if (memeq(sha512_oid, pos, sizeof(sha512_oid)))
274 {
275 hasher = hasher_create(HASH_SHA512);
276 pos += sizeof(sha512_oid);
277 }
278
279 if (hasher == NULL)
280 {
281 /* unsupported hash algorithm */
282 res = NOT_SUPPORTED;;
283 goto end;
284 }
285
286 if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len)
287 {
288 /* bad length */
289 hasher->destroy(hasher);
290 goto end;
291 }
292
293 /* build our own hash */
294 hasher->allocate_hash(hasher, data, &hash);
295 hasher->destroy(hasher);
296
297 /* compare the hashes */
298 res = memeq(hash.ptr, pos, hash.len) ? SUCCESS : FAILED;
299 free(hash.ptr);
300
301 end:
302 free(em.ptr);
303 return res;
304 }
305
306 /**
307 * Implementation of rsa_public_key.get_key.
308 */
309 static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key)
310 {
311 chunk_t n, e;
312
313 n.len = this->k;
314 n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
315 e.len = this->k;
316 e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
317
318 key->len = this->k * 2;
319 key->ptr = malloc(key->len);
320 memcpy(key->ptr, n.ptr, n.len);
321 memcpy(key->ptr + n.len, e.ptr, e.len);
322 free(n.ptr);
323 free(e.ptr);
324
325 return SUCCESS;
326 }
327
328 /**
329 * Implementation of rsa_public_key.save_key.
330 */
331 static status_t save_key(const private_rsa_public_key_t *this, char *file)
332 {
333 return NOT_SUPPORTED;
334 }
335
336 /**
337 * Implementation of rsa_public_key.get_modulus.
338 */
339 static mpz_t *get_modulus(const private_rsa_public_key_t *this)
340 {
341 return (mpz_t*)&this->n;
342 }
343
344 /**
345 * Implementation of rsa_public_key.get_keysize.
346 */
347 static size_t get_keysize(const private_rsa_public_key_t *this)
348 {
349 return this->k;
350 }
351
352 /**
353 * Implementation of rsa_public_key.get_keyid.
354 */
355 static chunk_t get_keyid(const private_rsa_public_key_t *this)
356 {
357 return this->keyid;
358 }
359
360 /**
361 * Implementation of rsa_public_key.clone.
362 */
363 static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
364 {
365 private_rsa_public_key_t *clone = rsa_public_key_create_empty();
366
367 mpz_init_set(clone->n, this->n);
368 mpz_init_set(clone->e, this->e);
369 clone->keyid = chunk_clone(this->keyid);
370 clone->k = this->k;
371
372 return &clone->public;
373 }
374
375 /**
376 * Implementation of rsa_public_key.destroy.
377 */
378 static void destroy(private_rsa_public_key_t *this)
379 {
380 mpz_clear(this->n);
381 mpz_clear(this->e);
382 free(this->keyid.ptr);
383 free(this);
384 }
385
386 /**
387 * Generic private constructor
388 */
389 private_rsa_public_key_t *rsa_public_key_create_empty(void)
390 {
391 private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
392
393 /* public functions */
394 this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
395 this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key;
396 this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key;
397 this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus;
398 this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize;
399 this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid;
400 this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone;
401 this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
402
403 /* private functions */
404 this->rsaep = rsaep;
405 this->rsavp1 = rsaep; /* same algorithm */
406
407 return this;
408 }
409
410 /**
411 * Build a DER-encoded publicKeyInfo object from an RSA public key.
412 * Also used in rsa_private_key.c.
413 */
414 chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
415 {
416 chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm",
417 asn1_integer_from_mpz(n),
418 asn1_integer_from_mpz(e));
419 chunk_t publicKey;
420
421 u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
422
423 *pos++ = 0x00;
424 memcpy(pos, rawKey.ptr, rawKey.len);
425 free(rawKey.ptr);
426
427 return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
428 publicKey);
429 }
430
431 /*
432 * See header
433 */
434 rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
435 {
436 asn1_ctx_t ctx;
437 chunk_t object;
438 u_int level;
439 int objectID = 0;
440
441 private_rsa_public_key_t *this = rsa_public_key_create_empty();
442
443 mpz_init(this->n);
444 mpz_init(this->e);
445
446 asn1_init(&ctx, blob, 0, FALSE);
447
448 while (objectID < PUB_KEY_ROOF)
449 {
450 if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx))
451 {
452 destroy(this);
453 return FALSE;
454 }
455 switch (objectID)
456 {
457 case PUB_KEY_MODULUS:
458 mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
459 break;
460 case PUB_KEY_EXPONENT:
461 mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
462 break;
463 }
464 objectID++;
465 }
466
467 this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
468
469 /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
470 {
471 chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
472 hasher_t *hasher = hasher_create(HASH_SHA1);
473
474 hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
475 hasher->destroy(hasher);
476 free(publicKeyInfo.ptr);
477 }
478
479 return &this->public;
480 }
481
482 /*
483 * See header
484 */
485 rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
486 {
487 bool pgp = FALSE;
488 chunk_t chunk = CHUNK_INITIALIZER;
489 rsa_public_key_t *pubkey = NULL;
490
491 if (!pem_asn1_load_file(filename, "", "public key", &chunk, &pgp))
492 return NULL;
493
494 pubkey = rsa_public_key_create_from_chunk(chunk);
495 free(chunk.ptr);
496 return pubkey;
497 }