7eae5949d105df9d12fd3e8527e81bb12f9f1655
[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(DBG_LIB, "building data S-expression failed: %s",
87 gpg_strerror(err));
88 return FALSE;
89 }
90 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
91 signature.len, signature.ptr);
92 if (err)
93 {
94 DBG1(DBG_LIB, "building signature S-expression failed: %s",
95 gpg_strerror(err));
96 gcry_sexp_release(in);
97 return FALSE;
98 }
99 err = gcry_pk_verify(sig, in, this->key);
100 gcry_sexp_release(in);
101 gcry_sexp_release(sig);
102 if (err)
103 {
104 DBG1(DBG_LIB, "RSA signature verification failed: %s",
105 gpg_strerror(err));
106 return FALSE;
107 }
108 return TRUE;
109 }
110
111 /**
112 * Verification of an EMSA PKCS1 signature described in PKCS#1
113 */
114 static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
115 hash_algorithm_t algorithm, char *hash_name,
116 chunk_t data, chunk_t signature)
117 {
118 hasher_t *hasher;
119 chunk_t hash;
120 gcry_error_t err;
121 gcry_sexp_t in, sig;
122
123 hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
124 if (!hasher)
125 {
126 return FALSE;
127 }
128 hasher->allocate_hash(hasher, data, &hash);
129 hasher->destroy(hasher);
130
131 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
132 hash_name, hash.len, hash.ptr);
133 chunk_free(&hash);
134 if (err)
135 {
136 DBG1(DBG_LIB, "building data S-expression failed: %s",
137 gpg_strerror(err));
138 return FALSE;
139 }
140
141 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
142 signature.len, signature.ptr);
143 if (err)
144 {
145 DBG1(DBG_LIB, "building signature S-expression failed: %s",
146 gpg_strerror(err));
147 gcry_sexp_release(in);
148 return FALSE;
149 }
150 err = gcry_pk_verify(sig, in, this->key);
151 gcry_sexp_release(in);
152 gcry_sexp_release(sig);
153 if (err)
154 {
155 DBG1(DBG_LIB, "RSA signature verification failed: %s",
156 gpg_strerror(err));
157 return FALSE;
158 }
159 return TRUE;
160 }
161
162 METHOD(public_key_t, get_type, key_type_t,
163 private_gcrypt_rsa_public_key_t *this)
164 {
165 return KEY_RSA;
166 }
167
168 METHOD(public_key_t, verify, bool,
169 private_gcrypt_rsa_public_key_t *this, signature_scheme_t scheme,
170 chunk_t data, chunk_t signature)
171 {
172 switch (scheme)
173 {
174 case SIGN_RSA_EMSA_PKCS1_NULL:
175 return verify_raw(this, data, signature);
176 case SIGN_RSA_EMSA_PKCS1_MD5:
177 return verify_pkcs1(this, HASH_MD5, "md5", data, signature);
178 case SIGN_RSA_EMSA_PKCS1_SHA1:
179 return verify_pkcs1(this, HASH_SHA1, "sha1", data, signature);
180 case SIGN_RSA_EMSA_PKCS1_SHA224:
181 return verify_pkcs1(this, HASH_SHA224, "sha224", data, signature);
182 case SIGN_RSA_EMSA_PKCS1_SHA256:
183 return verify_pkcs1(this, HASH_SHA256, "sha256", data, signature);
184 case SIGN_RSA_EMSA_PKCS1_SHA384:
185 return verify_pkcs1(this, HASH_SHA384, "sha384", data, signature);
186 case SIGN_RSA_EMSA_PKCS1_SHA512:
187 return verify_pkcs1(this, HASH_SHA512, "sha512", data, signature);
188 default:
189 DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
190 signature_scheme_names, scheme);
191 return FALSE;
192 }
193 }
194
195 METHOD(public_key_t, encrypt_, bool,
196 private_gcrypt_rsa_public_key_t *this, encryption_scheme_t scheme,
197 chunk_t plain, chunk_t *encrypted)
198 {
199 gcry_sexp_t in, out;
200 gcry_error_t err;
201
202 if (scheme != ENCRYPT_RSA_PKCS1)
203 {
204 DBG1(DBG_LIB, "encryption scheme %N not supported",
205 encryption_scheme_names, scheme);
206 return FALSE;
207 }
208 /* "pkcs1" uses PKCS 1.5 (section 8.1) block type 2 encryption:
209 * 00 | 02 | RANDOM | 00 | DATA */
210 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(value %b))",
211 plain.len, plain.ptr);
212 if (err)
213 {
214 DBG1(DBG_LIB, "building encryption S-expression failed: %s",
215 gpg_strerror(err));
216 return FALSE;
217 }
218 err = gcry_pk_encrypt(&out, in, this->key);
219 gcry_sexp_release(in);
220 if (err)
221 {
222 DBG1(DBG_LIB, "encrypting data using pkcs1 failed: %s",
223 gpg_strerror(err));
224 return FALSE;
225 }
226 *encrypted = gcrypt_rsa_find_token(out, "a", this->key);
227 gcry_sexp_release(out);
228 return !!encrypted->len;
229 }
230
231 METHOD(public_key_t, get_keysize, size_t,
232 private_gcrypt_rsa_public_key_t *this)
233 {
234 return gcry_pk_get_nbits(this->key) / 8;
235 }
236
237 METHOD(public_key_t, get_encoding, bool,
238 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
239 chunk_t *encoding)
240 {
241 chunk_t n, e;
242 bool success;
243
244 n = gcrypt_rsa_find_token(this->key, "n", NULL);
245 e = gcrypt_rsa_find_token(this->key, "e", NULL);
246 success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
247 CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e,
248 CRED_PART_END);
249 chunk_free(&n);
250 chunk_free(&e);
251
252 return success;
253 }
254
255 METHOD(public_key_t, get_fingerprint, bool,
256 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
257 chunk_t *fp)
258 {
259 chunk_t n, e;
260 bool success;
261
262 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
263 {
264 return TRUE;
265 }
266 n = gcrypt_rsa_find_token(this->key, "n", NULL);
267 e = gcrypt_rsa_find_token(this->key, "e", NULL);
268
269 success = lib->encoding->encode(lib->encoding,
270 type, this, fp, CRED_PART_RSA_MODULUS, n,
271 CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
272 chunk_free(&n);
273 chunk_free(&e);
274 return success;
275 }
276
277 METHOD(public_key_t, get_ref, public_key_t*,
278 private_gcrypt_rsa_public_key_t *this)
279 {
280 ref_get(&this->ref);
281 return &this->public.key;
282 }
283
284 METHOD(public_key_t, destroy, void,
285 private_gcrypt_rsa_public_key_t *this)
286 {
287 if (ref_put(&this->ref))
288 {
289 gcry_sexp_release(this->key);
290 lib->encoding->clear_cache(lib->encoding, this);
291 free(this);
292 }
293 }
294
295 /**
296 * See header.
297 */
298 gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
299 va_list args)
300 {
301 private_gcrypt_rsa_public_key_t *this;
302 gcry_error_t err;
303 chunk_t n, e;
304
305 n = e = chunk_empty;
306 while (TRUE)
307 {
308 switch (va_arg(args, builder_part_t))
309 {
310 case BUILD_RSA_MODULUS:
311 n = va_arg(args, chunk_t);
312 continue;
313 case BUILD_RSA_PUB_EXP:
314 e = va_arg(args, chunk_t);
315 continue;
316 case BUILD_END:
317 break;
318 default:
319 return NULL;
320 }
321 break;
322 }
323
324 INIT(this,
325 .public.key = {
326 .get_type = _get_type,
327 .verify = _verify,
328 .encrypt = _encrypt_,
329 .equals = public_key_equals,
330 .get_keysize = _get_keysize,
331 .get_fingerprint = _get_fingerprint,
332 .has_fingerprint = public_key_has_fingerprint,
333 .get_encoding = _get_encoding,
334 .get_ref = _get_ref,
335 .destroy = _destroy,
336 },
337 .ref = 1,
338 );
339
340 err = gcry_sexp_build(&this->key, NULL, "(public-key(rsa(n %b)(e %b)))",
341 n.len, n.ptr, e.len, e.ptr);
342 if (err)
343 {
344 DBG1(DBG_LIB, "loading public key failed: %s", gpg_strerror(err));
345 free(this);
346 return NULL;
347 }
348
349 return &this->public;
350 }
351