RSA with OpenSSL
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_rsa_public_key.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "openssl_rsa_public_key.h"
19
20 #include <debug.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/rsa.h>
24 #include <openssl/x509.h>
25
26 typedef struct private_openssl_rsa_public_key_t private_openssl_rsa_public_key_t;
27
28 /**
29 * Private data structure with signing context.
30 */
31 struct private_openssl_rsa_public_key_t {
32 /**
33 * Public interface for this signer.
34 */
35 openssl_rsa_public_key_t public;
36
37 /**
38 * RSA object from OpenSSL
39 */
40 RSA *rsa;
41
42 /**
43 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
44 */
45 identification_t *keyid_info;
46
47 /**
48 * Keyid formed as a SHA-1 hash of a publicKey object
49 */
50 identification_t *keyid;
51
52 /**
53 * reference counter
54 */
55 refcount_t ref;
56 };
57
58 /**
59 * Verification of an EMPSA PKCS1 signature described in PKCS#1
60 */
61 static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this,
62 int type, chunk_t data, chunk_t signature)
63 {
64 bool valid = FALSE;
65 const EVP_MD *hasher = EVP_get_digestbynid(type);
66 if (!hasher)
67 {
68 return FALSE;
69 }
70
71 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
72 EVP_PKEY *key = EVP_PKEY_new();
73 if (!ctx || !key)
74 {
75 goto error;
76 }
77
78 if (!EVP_PKEY_set1_RSA(key, this->rsa))
79 {
80 goto error;
81 }
82
83 if (!EVP_VerifyInit_ex(ctx, hasher, NULL))
84 {
85 goto error;
86 }
87
88 if (!EVP_VerifyUpdate(ctx, data.ptr, data.len))
89 {
90 goto error;
91 }
92
93 /* remove any preceding 0-bytes from signature */
94 while (signature.len && *(signature.ptr) == 0x00)
95 {
96 signature.len -= 1;
97 signature.ptr++;
98 }
99
100 valid = (EVP_VerifyFinal(ctx, signature.ptr, signature.len, key) == 1);
101
102 error:
103 if (key)
104 {
105 EVP_PKEY_free(key);
106 }
107 if (ctx)
108 {
109 EVP_MD_CTX_destroy(ctx);
110 }
111 return valid;
112 }
113
114 /**
115 * Implementation of public_key_t.get_type.
116 */
117 static key_type_t get_type(private_openssl_rsa_public_key_t *this)
118 {
119 return KEY_RSA;
120 }
121
122 /**
123 * Implementation of public_key_t.verify.
124 */
125 static bool verify(private_openssl_rsa_public_key_t *this, signature_scheme_t scheme,
126 chunk_t data, chunk_t signature)
127 {
128 switch (scheme)
129 {
130 case SIGN_DEFAULT:
131 /* default is EMSA-PKCS1 using SHA1 */
132 case SIGN_RSA_EMSA_PKCS1_SHA1:
133 return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
134 case SIGN_RSA_EMSA_PKCS1_SHA256:
135 return verify_emsa_pkcs1_signature(this, NID_sha256, data, signature);
136 case SIGN_RSA_EMSA_PKCS1_SHA384:
137 return verify_emsa_pkcs1_signature(this, NID_sha384, data, signature);
138 case SIGN_RSA_EMSA_PKCS1_SHA512:
139 return verify_emsa_pkcs1_signature(this, NID_sha512, data, signature);
140 case SIGN_RSA_EMSA_PKCS1_MD5:
141 return verify_emsa_pkcs1_signature(this, NID_md5, data, signature);
142 default:
143 DBG1("signature scheme %N not supported in RSA",
144 signature_scheme_names, scheme);
145 return FALSE;
146 }
147 }
148
149 /**
150 * Implementation of public_key_t.get_keysize.
151 */
152 static bool encrypt(private_openssl_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain)
153 {
154 DBG1("RSA public key encryption not implemented");
155 return FALSE;
156 }
157
158 /**
159 * Implementation of public_key_t.get_keysize.
160 */
161 static size_t get_keysize(private_openssl_rsa_public_key_t *this)
162 {
163 return RSA_size(this->rsa);
164 }
165
166 /**
167 * Implementation of public_key_t.get_id.
168 */
169 static identification_t *get_id(private_openssl_rsa_public_key_t *this,
170 id_type_t type)
171 {
172 switch (type)
173 {
174 case ID_PUBKEY_INFO_SHA1:
175 return this->keyid_info;
176 case ID_PUBKEY_SHA1:
177 return this->keyid;
178 default:
179 return NULL;
180 }
181 }
182
183 /**
184 * Encodes the public key
185 */
186 static chunk_t get_encoding_raw(RSA *rsa)
187 {
188 chunk_t enc = chunk_alloc(i2d_RSAPublicKey(rsa, NULL));
189 u_char *p = enc.ptr;
190 i2d_RSAPublicKey(rsa, &p);
191 return enc;
192 }
193
194 /**
195 * Encodes the public key with the algorithm used
196 */
197 static chunk_t get_encoding_with_algo(RSA *rsa)
198 {
199 u_char *p;
200 chunk_t enc;
201 X509_PUBKEY *pubkey = X509_PUBKEY_new();
202
203 ASN1_OBJECT_free(pubkey->algor->algorithm);
204 pubkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
205
206 if (pubkey->algor->parameter == NULL ||
207 pubkey->algor->parameter->type != V_ASN1_NULL)
208 {
209 ASN1_TYPE_free(pubkey->algor->parameter);
210 pubkey->algor->parameter = ASN1_TYPE_new();
211 pubkey->algor->parameter->type = V_ASN1_NULL;
212 }
213
214 enc = get_encoding_raw(rsa);
215 M_ASN1_BIT_STRING_set(pubkey->public_key, enc.ptr, enc.len);
216 chunk_free(&enc);
217
218 enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL));
219 p = enc.ptr;
220 i2d_X509_PUBKEY(pubkey, &p);
221 X509_PUBKEY_free(pubkey);
222 return enc;
223 }
224
225 /*
226 * Implementation of public_key_t.get_encoding.
227 */
228 static chunk_t get_encoding(private_openssl_rsa_public_key_t *this)
229 {
230 return get_encoding_raw(this->rsa);
231 }
232
233 /**
234 * Implementation of public_key_t.get_ref.
235 */
236 static private_openssl_rsa_public_key_t* get_ref(private_openssl_rsa_public_key_t *this)
237 {
238 ref_get(&this->ref);
239 return this;
240 }
241
242 /**
243 * Implementation of openssl_rsa_public_key.destroy.
244 */
245 static void destroy(private_openssl_rsa_public_key_t *this)
246 {
247 if (ref_put(&this->ref))
248 {
249 if (this->rsa)
250 {
251 RSA_free(this->rsa);
252 }
253 DESTROY_IF(this->keyid);
254 DESTROY_IF(this->keyid_info);
255 free(this);
256 }
257 }
258
259 /**
260 * Generic private constructor
261 */
262 static private_openssl_rsa_public_key_t *openssl_rsa_public_key_create_empty()
263 {
264 private_openssl_rsa_public_key_t *this = malloc_thing(private_openssl_rsa_public_key_t);
265
266 this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
267 this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
268 this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt;
269 this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
270 this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
271 this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
272 this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
273 this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
274
275 this->keyid = NULL;
276 this->keyid_info = NULL;
277 this->ref = 1;
278
279 return this;
280 }
281
282 /**
283 * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
284 * Also used in openssl_rsa_private_key.c.
285 */
286 bool openssl_rsa_public_key_build_id(RSA *rsa, identification_t **keyid,
287 identification_t **keyid_info)
288 {
289 chunk_t publicKeyInfo, publicKey, hash;
290 hasher_t *hasher;
291
292 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
293 if (hasher == NULL)
294 {
295 DBG1("SHA1 hash algorithm not supported, unable to use RSA");
296 return FALSE;
297 }
298
299 publicKey = get_encoding_raw(rsa);
300
301 hasher->allocate_hash(hasher, publicKey, &hash);
302 *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
303 chunk_free(&hash);
304
305 publicKeyInfo = get_encoding_with_algo(rsa);
306
307 hasher->allocate_hash(hasher, publicKeyInfo, &hash);
308 *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash);
309 chunk_free(&hash);
310
311 hasher->destroy(hasher);
312 chunk_free(&publicKeyInfo);
313 chunk_free(&publicKey);
314
315 return TRUE;
316 }
317
318 /**
319 * Create a public key from BIGNUM values, used in openssl_rsa_private_key.c
320 */
321 openssl_rsa_public_key_t *openssl_rsa_public_key_create_from_n_e(BIGNUM *n, BIGNUM *e)
322 {
323 private_openssl_rsa_public_key_t *this = openssl_rsa_public_key_create_empty();
324
325 this->rsa = RSA_new();
326 this->rsa->n = BN_dup(n);
327 this->rsa->e = BN_dup(e);
328
329 if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info))
330 {
331 destroy(this);
332 return NULL;
333 }
334 return &this->public;
335 }
336
337 /**
338 * Load a public key from an ASN1 encoded blob
339 */
340 static openssl_rsa_public_key_t *load(chunk_t blob)
341 {
342 u_char *p = blob.ptr;
343 private_openssl_rsa_public_key_t *this = openssl_rsa_public_key_create_empty();
344
345 this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&p, blob.len);
346
347 chunk_clear(&blob);
348
349 if (!this->rsa)
350 {
351 destroy(this);
352 return NULL;
353 }
354
355 if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info))
356 {
357 destroy(this);
358 return NULL;
359 }
360 return &this->public;
361 }
362
363 typedef struct private_builder_t private_builder_t;
364 /**
365 * Builder implementation for key loading
366 */
367 struct private_builder_t {
368 /** implements the builder interface */
369 builder_t public;
370 /** loaded public key */
371 openssl_rsa_public_key_t *key;
372 };
373
374 /**
375 * Implementation of builder_t.build
376 */
377 static openssl_rsa_public_key_t *build(private_builder_t *this)
378 {
379 openssl_rsa_public_key_t *key = this->key;
380
381 free(this);
382 return key;
383 }
384
385 /**
386 * Implementation of builder_t.add
387 */
388 static void add(private_builder_t *this, builder_part_t part, ...)
389 {
390 va_list args;
391
392 if (this->key)
393 {
394 DBG1("ignoring surplus build part %N", builder_part_names, part);
395 return;
396 }
397
398 switch (part)
399 {
400 case BUILD_BLOB_ASN1_DER:
401 {
402 va_start(args, part);
403 this->key = load(va_arg(args, chunk_t));
404 va_end(args);
405 break;
406 }
407 default:
408 DBG1("ignoring unsupported build part %N", builder_part_names, part);
409 break;
410 }
411 }
412
413 /**
414 * Builder construction function
415 */
416 builder_t *openssl_rsa_public_key_builder(key_type_t type)
417 {
418 private_builder_t *this;
419
420 if (type != KEY_RSA)
421 {
422 return NULL;
423 }
424
425 this = malloc_thing(private_builder_t);
426
427 this->key = NULL;
428 this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
429 this->public.build = (void*(*)(builder_t *this))build;
430
431 return &this->public;
432 }
433