]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
gcrypt: Support RSA OAEP SHA1 encryption/decryption
[people/ms/strongswan.git] / src / libstrongswan / plugins / gcrypt / gcrypt_rsa_public_key.c
1 /*
2 * Copyright (C) 2017 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <gcrypt.h>
18
19 #include "gcrypt_rsa_public_key.h"
20
21 #include <utils/debug.h>
22 #include <asn1/oid.h>
23 #include <asn1/asn1.h>
24 #include <asn1/asn1_parser.h>
25 #include <crypto/hashers/hasher.h>
26 #include <credentials/keys/signature_params.h>
27
28 typedef struct private_gcrypt_rsa_public_key_t private_gcrypt_rsa_public_key_t;
29
30 /**
31 * Private data structure with signing context.
32 */
33 struct private_gcrypt_rsa_public_key_t {
34
35 /**
36 * Public interface for this signer.
37 */
38 gcrypt_rsa_public_key_t public;
39
40 /**
41 * gcrypt S-expression representing an public RSA key
42 */
43 gcry_sexp_t key;
44
45 /**
46 * reference counter
47 */
48 refcount_t ref;
49 };
50
51 /**
52 * Implemented in gcrypt_rsa_private_key.c
53 */
54 chunk_t gcrypt_rsa_find_token(gcry_sexp_t sexp, char *name, gcry_sexp_t key);
55
56 /**
57 * verification of a padded PKCS1 signature without an OID
58 */
59 static bool verify_raw(private_gcrypt_rsa_public_key_t *this,
60 chunk_t data, chunk_t signature)
61 {
62 gcry_sexp_t in, sig;
63 gcry_error_t err;
64 chunk_t em;
65 size_t k;
66
67 /* EM = 0x00 || 0x01 || PS || 0x00 || T
68 * PS = 0xFF padding, with length to fill em
69 * T = data
70 */
71 k = gcry_pk_get_nbits(this->key) / 8;
72 if (data.len > k - 3)
73 {
74 return FALSE;
75 }
76 em = chunk_alloc(k);
77 memset(em.ptr, 0xFF, em.len);
78 em.ptr[0] = 0x00;
79 em.ptr[1] = 0x01;
80 em.ptr[em.len - data.len - 1] = 0x00;
81 memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
82
83 err = gcry_sexp_build(&in, NULL, "(data(flags raw)(value %b))",
84 em.len, em.ptr);
85 chunk_free(&em);
86 if (err)
87 {
88 DBG1(DBG_LIB, "building data S-expression failed: %s",
89 gpg_strerror(err));
90 return FALSE;
91 }
92 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
93 signature.len, signature.ptr);
94 if (err)
95 {
96 DBG1(DBG_LIB, "building signature S-expression failed: %s",
97 gpg_strerror(err));
98 gcry_sexp_release(in);
99 return FALSE;
100 }
101 err = gcry_pk_verify(sig, in, this->key);
102 gcry_sexp_release(in);
103 gcry_sexp_release(sig);
104 if (err)
105 {
106 DBG1(DBG_LIB, "RSA signature verification failed: %s",
107 gpg_strerror(err));
108 return FALSE;
109 }
110 return TRUE;
111 }
112
113 /**
114 * Verification of an EMSA PKCS1v1.5 / EMSA-PSS signature described in PKCS#1
115 */
116 static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
117 hash_algorithm_t algorithm, rsa_pss_params_t *pss,
118 chunk_t data, chunk_t signature)
119 {
120 hasher_t *hasher;
121 chunk_t hash;
122 gcry_error_t err;
123 gcry_sexp_t in, sig;
124 char *hash_name = enum_to_name(hash_algorithm_short_names, algorithm);
125
126 hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
127 if (!hasher)
128 {
129 DBG1(DBG_LIB, "hash algorithm %N not supported",
130 hash_algorithm_names, algorithm);
131 return FALSE;
132 }
133 if (!hasher->allocate_hash(hasher, data, &hash))
134 {
135 hasher->destroy(hasher);
136 return FALSE;
137 }
138 hasher->destroy(hasher);
139
140 if (pss)
141 {
142 u_int slen = pss->salt_len;
143 err = gcry_sexp_build(&in, NULL,
144 "(data(flags pss)(salt-length %u)(hash %s %b))",
145 slen, hash_name, hash.len, hash.ptr);
146 }
147 else
148 {
149 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
150 hash_name, hash.len, hash.ptr);
151 }
152 chunk_free(&hash);
153 if (err)
154 {
155 DBG1(DBG_LIB, "building data S-expression failed: %s",
156 gpg_strerror(err));
157 return FALSE;
158 }
159
160 err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
161 signature.len, signature.ptr);
162 if (err)
163 {
164 DBG1(DBG_LIB, "building signature S-expression failed: %s",
165 gpg_strerror(err));
166 gcry_sexp_release(in);
167 return FALSE;
168 }
169 err = gcry_pk_verify(sig, in, this->key);
170 gcry_sexp_release(in);
171 gcry_sexp_release(sig);
172 if (err)
173 {
174 DBG1(DBG_LIB, "RSA signature verification failed: %s",
175 gpg_strerror(err));
176 return FALSE;
177 }
178 return TRUE;
179 }
180
181 #if GCRYPT_VERSION_NUMBER >= 0x010700
182 /**
183 * Verification of an EMSA-PSS signature described in PKCS#1
184 */
185 static bool verify_pss(private_gcrypt_rsa_public_key_t *this,
186 rsa_pss_params_t *params, chunk_t data, chunk_t sig)
187 {
188 if (!params)
189 {
190 return FALSE;
191 }
192 if (params->mgf1_hash != params->hash)
193 {
194 DBG1(DBG_LIB, "unable to use a different MGF1 hash for RSA-PSS");
195 return FALSE;
196 }
197 return verify_pkcs1(this, params->hash, params, data, sig);
198 }
199 #endif
200
201 METHOD(public_key_t, get_type, key_type_t,
202 private_gcrypt_rsa_public_key_t *this)
203 {
204 return KEY_RSA;
205 }
206
207 METHOD(public_key_t, verify, bool,
208 private_gcrypt_rsa_public_key_t *this, signature_scheme_t scheme,
209 void *params, chunk_t data, chunk_t signature)
210 {
211 switch (scheme)
212 {
213 case SIGN_RSA_EMSA_PKCS1_NULL:
214 return verify_raw(this, data, signature);
215 case SIGN_RSA_EMSA_PKCS1_SHA2_224:
216 return verify_pkcs1(this, HASH_SHA224, NULL, data, signature);
217 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
218 return verify_pkcs1(this, HASH_SHA256, NULL, data, signature);
219 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
220 return verify_pkcs1(this, HASH_SHA384, NULL, data, signature);
221 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
222 return verify_pkcs1(this, HASH_SHA512, NULL, data, signature);
223 case SIGN_RSA_EMSA_PKCS1_SHA1:
224 return verify_pkcs1(this, HASH_SHA1, NULL, data, signature);
225 case SIGN_RSA_EMSA_PKCS1_MD5:
226 return verify_pkcs1(this, HASH_MD5, NULL, data, signature);
227 #if GCRYPT_VERSION_NUMBER >= 0x010700
228 case SIGN_RSA_EMSA_PSS:
229 return verify_pss(this, params, data, signature);
230 #endif
231 default:
232 DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
233 signature_scheme_names, scheme);
234 return FALSE;
235 }
236 }
237
238 METHOD(public_key_t, encrypt_, bool,
239 private_gcrypt_rsa_public_key_t *this, encryption_scheme_t scheme,
240 void *params, chunk_t plain, chunk_t *encrypted)
241 {
242 gcry_error_t err;
243 gcry_sexp_t in, out;
244 chunk_t label = chunk_empty;
245 u_char *sexp;
246
247 switch (scheme)
248 {
249 case ENCRYPT_RSA_PKCS1:
250 sexp = "(data(flags pkcs1)(value %b))";
251 break;
252 case ENCRYPT_RSA_OAEP_SHA1:
253 sexp = "(data(flags oaep)(value %b))";
254 break;
255 default:
256 DBG1(DBG_LIB, "encryption scheme %N not supported",
257 encryption_scheme_names, scheme);
258 return FALSE;
259 }
260
261 if (scheme == ENCRYPT_RSA_OAEP_SHA1 && params != NULL)
262 {
263 label = *(chunk_t *)params;
264 if (label.len > 0)
265 {
266 DBG1(DBG_LIB, "RSA OAEP encryption with a label not supported");
267 return FALSE;
268 }
269 }
270
271 err = gcry_sexp_build(&in, NULL, sexp, plain.len, plain.ptr);
272 if (err)
273 {
274 DBG1(DBG_LIB, "building encryption S-expression failed: %s",
275 gpg_strerror(err));
276 return FALSE;
277 }
278
279 err = gcry_pk_encrypt(&out, in, this->key);
280 gcry_sexp_release(in);
281 if (err)
282 {
283 DBG1(DBG_LIB, "RSA encryption failed: %s", gpg_strerror(err));
284 return FALSE;
285 }
286
287 *encrypted = gcrypt_rsa_find_token(out, "a", this->key);
288 gcry_sexp_release(out);
289
290 return encrypted->len > 0;
291 }
292
293 METHOD(public_key_t, get_keysize, int,
294 private_gcrypt_rsa_public_key_t *this)
295 {
296 return gcry_pk_get_nbits(this->key);
297 }
298
299 METHOD(public_key_t, get_encoding, bool,
300 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
301 chunk_t *encoding)
302 {
303 chunk_t n, e;
304 bool success;
305
306 n = gcrypt_rsa_find_token(this->key, "n", NULL);
307 e = gcrypt_rsa_find_token(this->key, "e", NULL);
308 success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
309 CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e,
310 CRED_PART_END);
311 chunk_free(&n);
312 chunk_free(&e);
313
314 return success;
315 }
316
317 METHOD(public_key_t, get_fingerprint, bool,
318 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
319 chunk_t *fp)
320 {
321 chunk_t n, e;
322 bool success;
323
324 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
325 {
326 return TRUE;
327 }
328 n = gcrypt_rsa_find_token(this->key, "n", NULL);
329 e = gcrypt_rsa_find_token(this->key, "e", NULL);
330
331 success = lib->encoding->encode(lib->encoding,
332 type, this, fp, CRED_PART_RSA_MODULUS, n,
333 CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
334 chunk_free(&n);
335 chunk_free(&e);
336 return success;
337 }
338
339 METHOD(public_key_t, get_ref, public_key_t*,
340 private_gcrypt_rsa_public_key_t *this)
341 {
342 ref_get(&this->ref);
343 return &this->public.key;
344 }
345
346 METHOD(public_key_t, destroy, void,
347 private_gcrypt_rsa_public_key_t *this)
348 {
349 if (ref_put(&this->ref))
350 {
351 gcry_sexp_release(this->key);
352 lib->encoding->clear_cache(lib->encoding, this);
353 free(this);
354 }
355 }
356
357 /**
358 * See header.
359 */
360 gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
361 va_list args)
362 {
363 private_gcrypt_rsa_public_key_t *this;
364 gcry_error_t err;
365 chunk_t n, e;
366
367 n = e = chunk_empty;
368 while (TRUE)
369 {
370 switch (va_arg(args, builder_part_t))
371 {
372 case BUILD_RSA_MODULUS:
373 n = va_arg(args, chunk_t);
374 continue;
375 case BUILD_RSA_PUB_EXP:
376 e = va_arg(args, chunk_t);
377 continue;
378 case BUILD_END:
379 break;
380 default:
381 return NULL;
382 }
383 break;
384 }
385
386 INIT(this,
387 .public = {
388 .key = {
389 .get_type = _get_type,
390 .verify = _verify,
391 .encrypt = _encrypt_,
392 .equals = public_key_equals,
393 .get_keysize = _get_keysize,
394 .get_fingerprint = _get_fingerprint,
395 .has_fingerprint = public_key_has_fingerprint,
396 .get_encoding = _get_encoding,
397 .get_ref = _get_ref,
398 .destroy = _destroy,
399 },
400 },
401 .ref = 1,
402 );
403
404 err = gcry_sexp_build(&this->key, NULL, "(public-key(rsa(n %b)(e %b)))",
405 n.len, n.ptr, e.len, e.ptr);
406 if (err)
407 {
408 DBG1(DBG_LIB, "loading public key failed: %s", gpg_strerror(err));
409 free(this);
410 return NULL;
411 }
412
413 return &this->public;
414 }
415