]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
bbfa5e29800f36a424f2a848fb8c1e38e0e67cbd
[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 chunk_t plain, chunk_t *encrypted)
241 {
242 gcry_sexp_t in, out;
243 gcry_error_t err;
244
245 if (scheme != ENCRYPT_RSA_PKCS1)
246 {
247 DBG1(DBG_LIB, "encryption scheme %N not supported",
248 encryption_scheme_names, scheme);
249 return FALSE;
250 }
251 /* "pkcs1" uses PKCS 1.5 (section 8.1) block type 2 encryption:
252 * 00 | 02 | RANDOM | 00 | DATA */
253 err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(value %b))",
254 plain.len, plain.ptr);
255 if (err)
256 {
257 DBG1(DBG_LIB, "building encryption S-expression failed: %s",
258 gpg_strerror(err));
259 return FALSE;
260 }
261 err = gcry_pk_encrypt(&out, in, this->key);
262 gcry_sexp_release(in);
263 if (err)
264 {
265 DBG1(DBG_LIB, "encrypting data using pkcs1 failed: %s",
266 gpg_strerror(err));
267 return FALSE;
268 }
269 *encrypted = gcrypt_rsa_find_token(out, "a", this->key);
270 gcry_sexp_release(out);
271 return !!encrypted->len;
272 }
273
274 METHOD(public_key_t, get_keysize, int,
275 private_gcrypt_rsa_public_key_t *this)
276 {
277 return gcry_pk_get_nbits(this->key);
278 }
279
280 METHOD(public_key_t, get_encoding, bool,
281 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
282 chunk_t *encoding)
283 {
284 chunk_t n, e;
285 bool success;
286
287 n = gcrypt_rsa_find_token(this->key, "n", NULL);
288 e = gcrypt_rsa_find_token(this->key, "e", NULL);
289 success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
290 CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e,
291 CRED_PART_END);
292 chunk_free(&n);
293 chunk_free(&e);
294
295 return success;
296 }
297
298 METHOD(public_key_t, get_fingerprint, bool,
299 private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
300 chunk_t *fp)
301 {
302 chunk_t n, e;
303 bool success;
304
305 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
306 {
307 return TRUE;
308 }
309 n = gcrypt_rsa_find_token(this->key, "n", NULL);
310 e = gcrypt_rsa_find_token(this->key, "e", NULL);
311
312 success = lib->encoding->encode(lib->encoding,
313 type, this, fp, CRED_PART_RSA_MODULUS, n,
314 CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
315 chunk_free(&n);
316 chunk_free(&e);
317 return success;
318 }
319
320 METHOD(public_key_t, get_ref, public_key_t*,
321 private_gcrypt_rsa_public_key_t *this)
322 {
323 ref_get(&this->ref);
324 return &this->public.key;
325 }
326
327 METHOD(public_key_t, destroy, void,
328 private_gcrypt_rsa_public_key_t *this)
329 {
330 if (ref_put(&this->ref))
331 {
332 gcry_sexp_release(this->key);
333 lib->encoding->clear_cache(lib->encoding, this);
334 free(this);
335 }
336 }
337
338 /**
339 * See header.
340 */
341 gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
342 va_list args)
343 {
344 private_gcrypt_rsa_public_key_t *this;
345 gcry_error_t err;
346 chunk_t n, e;
347
348 n = e = chunk_empty;
349 while (TRUE)
350 {
351 switch (va_arg(args, builder_part_t))
352 {
353 case BUILD_RSA_MODULUS:
354 n = va_arg(args, chunk_t);
355 continue;
356 case BUILD_RSA_PUB_EXP:
357 e = va_arg(args, chunk_t);
358 continue;
359 case BUILD_END:
360 break;
361 default:
362 return NULL;
363 }
364 break;
365 }
366
367 INIT(this,
368 .public = {
369 .key = {
370 .get_type = _get_type,
371 .verify = _verify,
372 .encrypt = _encrypt_,
373 .equals = public_key_equals,
374 .get_keysize = _get_keysize,
375 .get_fingerprint = _get_fingerprint,
376 .has_fingerprint = public_key_has_fingerprint,
377 .get_encoding = _get_encoding,
378 .get_ref = _get_ref,
379 .destroy = _destroy,
380 },
381 },
382 .ref = 1,
383 );
384
385 err = gcry_sexp_build(&this->key, NULL, "(public-key(rsa(n %b)(e %b)))",
386 n.len, n.ptr, e.len, e.ptr);
387 if (err)
388 {
389 DBG1(DBG_LIB, "loading public key failed: %s", gpg_strerror(err));
390 free(this);
391 return NULL;
392 }
393
394 return &this->public;
395 }
396