Updated gcrypt plugin to the new builder API
[strongswan.git] / src / libstrongswan / plugins / gcrypt / gcrypt_rsa_public_key.c
1 /*
2 * Copyright (C) 2005-2009 Martin Willi
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
16 #include <gcrypt.h>
17
18 #include "gcrypt_rsa_public_key.h"
19
20 #include <debug.h>
21 #include <asn1/oid.h>
22 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
24 #include <crypto/hashers/hasher.h>
25
26 typedef struct private_gcrypt_rsa_public_key_t private_gcrypt_rsa_public_key_t;
27
28 /**
29 * Private data structure with signing context.
30 */
31 struct private_gcrypt_rsa_public_key_t {
32
33 /**
34 * Public interface for this signer.
35 */
36 gcrypt_rsa_public_key_t public;
37
38 /**
39 * gcrypt S-expression representing an public RSA key
40 */
41 gcry_sexp_t key;
42
43 /**
44 * reference counter
45 */
46 refcount_t ref;
47 };
48
49 /**
50 * Implemented in gcrypt_rsa_private_key.c
51 */
52 chunk_t gcrypt_rsa_find_token(gcry_sexp_t sexp, char *name, gcry_sexp_t key);
53
54 /**
55 * verification of a padded PKCS1 signature without an OID
56 */
57 static bool verify_raw(private_gcrypt_rsa_public_key_t *this,
58 chunk_t data, chunk_t signature)
59 {
60 gcry_sexp_t in, sig;
61 gcry_error_t err;
62 chunk_t em;
63 size_t k;
64
65 /* EM = 0x00 || 0x01 || PS || 0x00 || T
66 * PS = 0xFF padding, with length to fill em
67 * T = data
68 */
69 k = gcry_pk_get_nbits(this->key) / 8;
70 if (data.len > k - 3)
71 {
72 return FALSE;
73 }
74 em = chunk_alloc(k);
75 memset(em.ptr, 0xFF, em.len);
76 em.ptr[0] = 0x00;
77 em.ptr[1] = 0x01;
78 em.ptr[em.len - data.len - 1] = 0x00;
79 memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
80
81 err = gcry_sexp_build(&in, NULL, "(data(flags raw)(value %b))",
82 em.len, em.ptr);
83 chunk_free(&em);
84 if (err)
85 {
86 DBG1("building data S-expression failed: %s", gpg_strerror(err));
87 return FALSE;
88 }
89 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
90 signature.len, signature.ptr);
91 if (err)
92 {
93 DBG1("building signature S-expression failed: %s", gpg_strerror(err));
94 gcry_sexp_release(in);
95 return FALSE;
96 }
97 err = gcry_pk_verify(sig, in, this->key);
98 gcry_sexp_release(in);
99 gcry_sexp_release(sig);
100 if (err)
101 {
102 DBG1("RSA signature verification failed: %s", gpg_strerror(err));
103 return FALSE;
104 }
105 return TRUE;
106 }
107
108 /**
109 * Verification of an EMSA PKCS1 signature described in PKCS#1
110 */
111 static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
112 hash_algorithm_t algorithm, char *hash_name,
113 chunk_t data, chunk_t signature)
114 {
115 hasher_t *hasher;
116 chunk_t hash;
117 gcry_error_t err;
118 gcry_sexp_t in, sig;
119
120 hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
121 if (!hasher)
122 {
123 return FALSE;
124 }
125 hasher->allocate_hash(hasher, data, &hash);
126 hasher->destroy(hasher);
127
128 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
129 hash_name, hash.len, hash.ptr);
130 chunk_free(&hash);
131 if (err)
132 {
133 DBG1("building data S-expression failed: %s", gpg_strerror(err));
134 return FALSE;
135 }
136
137 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
138 signature.len, signature.ptr);
139 if (err)
140 {
141 DBG1("building signature S-expression failed: %s", gpg_strerror(err));
142 gcry_sexp_release(in);
143 return FALSE;
144 }
145 err = gcry_pk_verify(sig, in, this->key);
146 gcry_sexp_release(in);
147 gcry_sexp_release(sig);
148 if (err)
149 {
150 DBG1("RSA signature verification failed: %s", gpg_strerror(err));
151 return FALSE;
152 }
153 return TRUE;
154 }
155
156 /**
157 * Implementation of public_key_t.get_type.
158 */
159 static key_type_t get_type(private_gcrypt_rsa_public_key_t *this)
160 {
161 return KEY_RSA;
162 }
163
164 /**
165 * Implementation of public_key_t.verify.
166 */
167 static bool verify(private_gcrypt_rsa_public_key_t *this,
168 signature_scheme_t scheme, chunk_t data, chunk_t signature)
169 {
170 switch (scheme)
171 {
172 case SIGN_RSA_EMSA_PKCS1_NULL:
173 return verify_raw(this, data, signature);
174 case SIGN_RSA_EMSA_PKCS1_MD5:
175 return verify_pkcs1(this, HASH_MD5, "md5", data, signature);
176 case SIGN_RSA_EMSA_PKCS1_SHA1:
177 return verify_pkcs1(this, HASH_SHA1, "sha1", data, signature);
178 case SIGN_RSA_EMSA_PKCS1_SHA224:
179 return verify_pkcs1(this, HASH_SHA224, "sha224", data, signature);
180 case SIGN_RSA_EMSA_PKCS1_SHA256:
181 return verify_pkcs1(this, HASH_SHA256, "sha256", data, signature);
182 case SIGN_RSA_EMSA_PKCS1_SHA384:
183 return verify_pkcs1(this, HASH_SHA384, "sha384", data, signature);
184 case SIGN_RSA_EMSA_PKCS1_SHA512:
185 return verify_pkcs1(this, HASH_SHA512, "sha512", data, signature);
186 default:
187 DBG1("signature scheme %N not supported in RSA",
188 signature_scheme_names, scheme);
189 return FALSE;
190 }
191 }
192
193 /**
194 * Implementation of public_key_t.encrypt.
195 */
196 static bool encrypt_(private_gcrypt_rsa_public_key_t *this, chunk_t plain,
197 chunk_t *encrypted)
198 {
199 gcry_sexp_t in, out;
200 gcry_error_t err;
201
202 /* "pkcs1" uses PKCS 1.5 (section 8.1) block type 2 encryption:
203 * 00 | 02 | RANDOM | 00 | DATA */
204 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(value %b))",
205 plain.len, plain.ptr);
206 if (err)
207 {
208 DBG1("building encryption S-expression failed: %s", gpg_strerror(err));
209 return FALSE;
210 }
211 err = gcry_pk_encrypt(&out, in, this->key);
212 gcry_sexp_release(in);
213 if (err)
214 {
215 DBG1("encrypting data using pkcs1 failed: %s", gpg_strerror(err));
216 return FALSE;
217 }
218 *encrypted = gcrypt_rsa_find_token(out, "a", this->key);
219 gcry_sexp_release(out);
220 return !!encrypted->len;
221 }
222
223 /**
224 * Implementation of public_key_t.get_keysize.
225 */
226 static size_t get_keysize(private_gcrypt_rsa_public_key_t *this)
227 {
228 return gcry_pk_get_nbits(this->key) / 8;
229 }
230
231 /**
232 * Implementation of private_key_t.get_encoding
233 */
234 static bool get_encoding(private_gcrypt_rsa_public_key_t *this,
235 key_encoding_type_t type, chunk_t *encoding)
236 {
237 chunk_t n, e;
238 bool success;
239
240 n = gcrypt_rsa_find_token(this->key, "n", NULL);
241 e = gcrypt_rsa_find_token(this->key, "e", NULL);
242 success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
243 KEY_PART_RSA_MODULUS, n, KEY_PART_RSA_PUB_EXP, e,
244 KEY_PART_END);
245 chunk_free(&n);
246 chunk_free(&e);
247
248 return success;
249 }
250
251 /**
252 * Implementation of private_key_t.get_fingerprint
253 */
254 static bool get_fingerprint(private_gcrypt_rsa_public_key_t *this,
255 key_encoding_type_t type, chunk_t *fp)
256 {
257 chunk_t n, e;
258 bool success;
259
260 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
261 {
262 return TRUE;
263 }
264 n = gcrypt_rsa_find_token(this->key, "n", NULL);
265 e = gcrypt_rsa_find_token(this->key, "e", NULL);
266
267 success = lib->encoding->encode(lib->encoding,
268 type, this, fp, KEY_PART_RSA_MODULUS, n,
269 KEY_PART_RSA_PUB_EXP, e, KEY_PART_END);
270 chunk_free(&n);
271 chunk_free(&e);
272 return success;
273 }
274
275 /**
276 * Implementation of public_key_t.get_ref.
277 */
278 static public_key_t* get_ref(private_gcrypt_rsa_public_key_t *this)
279 {
280 ref_get(&this->ref);
281 return &this->public.interface;
282 }
283
284 /**
285 * Implementation of gcrypt_rsa_public_key.destroy.
286 */
287 static void destroy(private_gcrypt_rsa_public_key_t *this)
288 {
289 if (ref_put(&this->ref))
290 {
291 gcry_sexp_release(this->key);
292 lib->encoding->clear_cache(lib->encoding, this);
293 free(this);
294 }
295 }
296
297 /**
298 * See header.
299 */
300 gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
301 va_list args)
302 {
303 private_gcrypt_rsa_public_key_t *this;
304 gcry_error_t err;
305 chunk_t n, e;
306
307 n = e = chunk_empty;
308 while (TRUE)
309 {
310 switch (va_arg(args, builder_part_t))
311 {
312 case BUILD_RSA_MODULUS:
313 n = va_arg(args, chunk_t);
314 continue;
315 case BUILD_RSA_PUB_EXP:
316 e = va_arg(args, chunk_t);
317 continue;
318 case BUILD_END:
319 break;
320 default:
321 return NULL;
322 }
323 break;
324 }
325
326 this = malloc_thing(private_gcrypt_rsa_public_key_t);
327
328 this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
329 this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
330 this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
331 this->public.interface.equals = public_key_equals;
332 this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
333 this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint;
334 this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding;
335 this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
336 this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
337
338 this->key = NULL;
339 this->ref = 1;
340
341 err = gcry_sexp_build(&this->key, NULL, "(public-key(rsa(n %b)(e %b)))",
342 n.len, n.ptr, e.len, e.ptr);
343 if (err)
344 {
345 DBG1("loading public key failed: %s", gpg_strerror(err));
346 free(this);
347 return NULL;
348 }
349
350 return &this->public;
351 }
352