added error messages in signature verification
[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 <debug.h>
33 #include <crypto/hashers/hasher.h>
34 #include <asn1/asn1.h>
35 #include <asn1/pem.h>
36
37 #define LARGEST_HASH_OID_SIZE sizeof(sha512_oid)
38
39 /* ASN.1 definition of RSApublicKey */
40 static const asn1Object_t pubkeyObjects[] = {
41 { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
42 { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */
43 { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */
44 };
45
46 #define PUB_KEY_RSA_PUBLIC_KEY 0
47 #define PUB_KEY_MODULUS 1
48 #define PUB_KEY_EXPONENT 2
49 #define PUB_KEY_ROOF 3
50
51 /* ASN.1 definition of digestInfo */
52 static const asn1Object_t digestInfoObjects[] = {
53 { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
54 { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
55 { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
56 };
57
58 #define DIGEST_INFO 0
59 #define DIGEST_INFO_ALGORITHM 1
60 #define DIGEST_INFO_DIGEST 2
61 #define DIGEST_INFO_ROOF 3
62
63 typedef struct private_rsa_public_key_t private_rsa_public_key_t;
64
65 /**
66 * Private data structure with signing context.
67 */
68 struct private_rsa_public_key_t {
69 /**
70 * Public interface for this signer.
71 */
72 rsa_public_key_t public;
73
74 /**
75 * Public modulus.
76 */
77 mpz_t n;
78
79 /**
80 * Public exponent.
81 */
82 mpz_t e;
83
84 /**
85 * Keysize in bytes.
86 */
87 size_t k;
88
89 /**
90 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
91 */
92 chunk_t keyid;
93
94 /**
95 * @brief Implements the RSAEP algorithm specified in PKCS#1.
96 *
97 * @param this calling object
98 * @param data data to process
99 * @return processed data
100 */
101 chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data);
102
103 /**
104 * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
105 *
106 * @param this calling object
107 * @param data data to process
108 * @return processed data
109 */
110 chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data);
111 };
112
113 private_rsa_public_key_t *rsa_public_key_create_empty(void);
114
115 /**
116 * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
117 */
118 static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
119 {
120 mpz_t m, c;
121 chunk_t encrypted;
122
123 mpz_init(c);
124 mpz_init(m);
125
126 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
127
128 mpz_powm(c, m, this->e, this->n);
129
130 encrypted.len = this->k;
131 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
132
133 mpz_clear(c);
134 mpz_clear(m);
135
136 return encrypted;
137 }
138
139 /**
140 * Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
141 */
142 static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this,
143 hash_algorithm_t algorithm,
144 chunk_t data, chunk_t signature)
145 {
146 chunk_t em_ori, em;
147 status_t res = FAILED;
148
149 /* remove any preceding 0-bytes from signature */
150 while (signature.len && *(signature.ptr) == 0x00)
151 {
152 signature.len -= 1;
153 signature.ptr++;
154 }
155
156 if (signature.len > this->k)
157 {
158 return INVALID_ARG;
159 }
160
161 /* unpack signature */
162 em_ori = em = this->rsavp1(this, signature);
163
164 /* result should look like this:
165 * EM = 0x00 || 0x01 || PS || 0x00 || T.
166 * PS = 0xFF padding, with length to fill em
167 * T = oid || hash
168 */
169
170 /* check magic bytes */
171 if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01)
172 {
173 goto end;
174 }
175 em.ptr += 2;
176 em.len -= 2;
177
178 /* find magic 0x00 */
179 while (em.len > 0)
180 {
181 if (*em.ptr == 0x00)
182 {
183 /* found magic byte, stop */
184 em.ptr++;
185 em.len--;
186 break;
187 }
188 else if (*em.ptr != 0xFF)
189 {
190 /* bad padding, decryption failed ?!*/
191 goto end;
192 }
193 em.ptr++;
194 em.len--;
195 }
196
197 if (em.len == 0)
198 {
199 /* no digestInfo found */
200 goto end;
201 }
202
203 /* parse ASN.1-based digestInfo */
204 {
205 asn1_ctx_t ctx;
206 chunk_t object;
207 u_int level;
208 int objectID = 0;
209 hash_algorithm_t hash_algorithm;
210
211 asn1_init(&ctx, em, 0, FALSE, FALSE);
212
213 while (objectID < DIGEST_INFO_ROOF)
214 {
215 if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx))
216 {
217 goto end;
218 }
219 switch (objectID)
220 {
221 case DIGEST_INFO:
222 if (em.len > object.len)
223 {
224 DBG1("digestInfo field in signature is followed by %u surplus bytes",
225 em.len - object.len);
226 goto end;
227 }
228 break;
229 case DIGEST_INFO_ALGORITHM:
230 {
231 int hash_oid = parse_algorithmIdentifier(object, level+1, NULL);
232
233 hash_algorithm = hasher_algorithm_from_oid(hash_oid);
234 if (hash_algorithm == HASH_UNKNOWN
235 || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
236 {
237 DBG1("wrong hash algorithm used in signature");
238 goto end;
239 }
240 }
241 break;
242 case DIGEST_INFO_DIGEST:
243 {
244 chunk_t hash;
245 hasher_t *hasher = hasher_create(hash_algorithm);
246
247 if (object.len != hasher->get_hash_size(hasher))
248 {
249 DBG1("wrong hash size in signature");
250 hasher->destroy(hasher);
251 goto end;
252 }
253
254 /* build our own hash */
255 hasher->allocate_hash(hasher, data, &hash);
256 hasher->destroy(hasher);
257
258 /* compare the hashes */
259 res = memeq(object.ptr, hash.ptr, hash.len) ? SUCCESS : FAILED;
260 free(hash.ptr);
261 }
262 break;
263 default:
264 break;
265 }
266 objectID++;
267 }
268 }
269
270 end:
271 free(em_ori.ptr);
272 return res;
273 }
274
275 /**
276 * Implementation of rsa_public_key.get_key.
277 */
278 static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key)
279 {
280 chunk_t n, e;
281
282 n.len = this->k;
283 n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
284 e.len = this->k;
285 e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
286
287 key->len = this->k * 2;
288 key->ptr = malloc(key->len);
289 memcpy(key->ptr, n.ptr, n.len);
290 memcpy(key->ptr + n.len, e.ptr, e.len);
291 free(n.ptr);
292 free(e.ptr);
293
294 return SUCCESS;
295 }
296
297 /**
298 * Implementation of rsa_public_key.save_key.
299 */
300 static status_t save_key(const private_rsa_public_key_t *this, char *file)
301 {
302 return NOT_SUPPORTED;
303 }
304
305 /**
306 * Implementation of rsa_public_key.get_modulus.
307 */
308 static mpz_t *get_modulus(const private_rsa_public_key_t *this)
309 {
310 return (mpz_t*)&this->n;
311 }
312
313 /**
314 * Implementation of rsa_public_key.get_keysize.
315 */
316 static size_t get_keysize(const private_rsa_public_key_t *this)
317 {
318 return this->k;
319 }
320
321 /**
322 * Implementation of rsa_public_key.get_keyid.
323 */
324 static chunk_t get_keyid(const private_rsa_public_key_t *this)
325 {
326 return this->keyid;
327 }
328
329 /**
330 * Implementation of rsa_public_key.clone.
331 */
332 static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
333 {
334 private_rsa_public_key_t *clone = rsa_public_key_create_empty();
335
336 mpz_init_set(clone->n, this->n);
337 mpz_init_set(clone->e, this->e);
338 clone->keyid = chunk_clone(this->keyid);
339 clone->k = this->k;
340
341 return &clone->public;
342 }
343
344 /**
345 * Implementation of rsa_public_key.destroy.
346 */
347 static void destroy(private_rsa_public_key_t *this)
348 {
349 mpz_clear(this->n);
350 mpz_clear(this->e);
351 free(this->keyid.ptr);
352 free(this);
353 }
354
355 /**
356 * Generic private constructor
357 */
358 private_rsa_public_key_t *rsa_public_key_create_empty(void)
359 {
360 private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
361
362 /* public functions */
363 this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
364 this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key;
365 this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key;
366 this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus;
367 this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize;
368 this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid;
369 this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone;
370 this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
371
372 /* private functions */
373 this->rsaep = rsaep;
374 this->rsavp1 = rsaep; /* same algorithm */
375
376 return this;
377 }
378
379 /**
380 * Build a DER-encoded publicKeyInfo object from an RSA public key.
381 * Also used in rsa_private_key.c.
382 */
383 chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
384 {
385 chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm",
386 asn1_integer_from_mpz(n),
387 asn1_integer_from_mpz(e));
388 chunk_t publicKey;
389
390 u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
391
392 *pos++ = 0x00;
393 memcpy(pos, rawKey.ptr, rawKey.len);
394 free(rawKey.ptr);
395
396 return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
397 publicKey);
398 }
399
400 /*
401 * See header
402 */
403 rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
404 {
405 asn1_ctx_t ctx;
406 chunk_t object;
407 u_int level;
408 int objectID = 0;
409
410 private_rsa_public_key_t *this = rsa_public_key_create_empty();
411
412 mpz_init(this->n);
413 mpz_init(this->e);
414
415 asn1_init(&ctx, blob, 0, FALSE, FALSE);
416
417 while (objectID < PUB_KEY_ROOF)
418 {
419 if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx))
420 {
421 destroy(this);
422 return FALSE;
423 }
424 switch (objectID)
425 {
426 case PUB_KEY_MODULUS:
427 mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
428 break;
429 case PUB_KEY_EXPONENT:
430 mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
431 break;
432 }
433 objectID++;
434 }
435
436 this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
437
438 /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
439 {
440 chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
441 hasher_t *hasher = hasher_create(HASH_SHA1);
442
443 hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
444 hasher->destroy(hasher);
445 free(publicKeyInfo.ptr);
446 }
447
448 return &this->public;
449 }
450
451 /*
452 * See header
453 */
454 rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
455 {
456 bool pgp = FALSE;
457 chunk_t chunk = chunk_empty;
458 rsa_public_key_t *pubkey = NULL;
459
460 if (!pem_asn1_load_file(filename, NULL, "public key", &chunk, &pgp))
461 return NULL;
462
463 pubkey = rsa_public_key_create_from_chunk(chunk);
464 free(chunk.ptr);
465 return pubkey;
466 }