signature-params: Add helper struct for signature scheme and parameters
[strongswan.git] / src / libstrongswan / credentials / keys / signature_params.c
1 /*
2 * Copyright (C) 2017 Tobias Brunner
3 * HSR 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 "signature_params.h"
17
18 #include <asn1/oid.h>
19 #include <asn1/asn1_parser.h>
20
21 /**
22 * Determine the salt length in case it is not configured
23 */
24 static ssize_t rsa_pss_salt_length(rsa_pss_params_t *pss)
25 {
26 ssize_t salt_len = pss->salt_len;
27
28 if (salt_len <= RSA_PSS_SALT_LEN_DEFAULT)
29 {
30 salt_len = hasher_hash_size(pss->hash);
31 if (!salt_len)
32 {
33 return -1;
34 }
35 }
36 return salt_len;
37 }
38
39 /**
40 * Compare two signature schemes and their parameters
41 */
42 static bool compare_params(signature_params_t *a, signature_params_t *b,
43 bool strict)
44 {
45 if (!a && !b)
46 {
47 return TRUE;
48 }
49 if (!a || !b)
50 {
51 return FALSE;
52 }
53 if (a->scheme != b->scheme)
54 {
55 return FALSE;
56 }
57 if (!a->params && !b->params)
58 {
59 return TRUE;
60 }
61 if (a->params && b->params)
62 {
63 switch (a->scheme)
64 {
65 case SIGN_RSA_EMSA_PSS:
66 {
67 rsa_pss_params_t *pss_a = a->params, *pss_b = b->params;
68
69 return pss_a->hash == pss_b->hash &&
70 pss_a->mgf1_hash == pss_b->mgf1_hash &&
71 (!strict ||
72 rsa_pss_salt_length(pss_a) == rsa_pss_salt_length(pss_b));
73 }
74 default:
75 break;
76 }
77 }
78 return FALSE;
79 }
80
81 /*
82 * Described in header
83 */
84 bool signature_params_equal(signature_params_t *a, signature_params_t *b)
85 {
86 return compare_params(a, b, TRUE);
87 }
88
89 /*
90 * Described in header
91 */
92 bool signature_params_comply(signature_params_t *c, signature_params_t *s)
93 { /* the salt is variable, so it does not necessarily have to be the same */
94 return compare_params(c, s, FALSE);
95 }
96
97 /*
98 * Described in header
99 */
100 signature_params_t *signature_params_clone(signature_params_t *this)
101 {
102 signature_params_t *clone;
103
104 if (!this)
105 {
106 return NULL;
107 }
108
109 INIT(clone,
110 .scheme = this->scheme,
111 );
112 if (this->params)
113 {
114 switch (this->scheme)
115 {
116 case SIGN_RSA_EMSA_PSS:
117 {
118 rsa_pss_params_t *pss, *pss_clone;
119
120 pss = this->params;
121 INIT(pss_clone,
122 .hash = pss->hash,
123 .mgf1_hash = pss->mgf1_hash,
124 .salt_len = pss->salt_len,
125 /* ignore salt as only used for unit tests */
126 );
127 clone->params = pss_clone;
128 break;
129 }
130 default:
131 break;
132 }
133 }
134 return clone;
135 }
136
137 /*
138 * Described in header
139 */
140 void signature_params_destroy(signature_params_t *this)
141 {
142 if (this)
143 {
144 free(this->params);
145 free(this);
146 }
147 }
148
149 /*
150 * Described in header
151 */
152 void signature_params_clear(signature_params_t *this)
153 {
154 if (this)
155 {
156 free(this->params);
157 this->params = NULL;
158 this->scheme = SIGN_UNKNOWN;
159 }
160 }
161
162 /**
163 * ASN.1 definition of RSASSA-PSS-params
164 */
165 static const asn1Object_t RSASSAPSSParamsObjects[] = {
166 { 0, "RSASSA-PSS-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
167 { 1, "DEFAULT SHA-1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 1 */
168 { 2, "hashAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
169 { 1, "DEFAULT MGF1SHA1", ASN1_CONTEXT_C_1, ASN1_DEF }, /* 3 */
170 { 2, "maskGenAlgorithm",ASN1_EOC, ASN1_RAW }, /* 4 */
171 { 1, "DEFAULT 20", ASN1_CONTEXT_C_2, ASN1_DEF }, /* 5 */
172 { 2, "saltLength", ASN1_INTEGER, ASN1_BODY }, /* 6 */
173 { 1, "DEFAULT 1", ASN1_CONTEXT_C_3, ASN1_DEF }, /* 7 */
174 { 2, "trailerField", ASN1_INTEGER, ASN1_BODY }, /* 8 */
175 { 0, "exit", ASN1_EOC, ASN1_EXIT }
176 };
177 #define RSASSA_PSS_PARAMS_HASH_ALG 2
178 #define RSASSA_PSS_PARAMS_MGF_ALG 4
179 #define RSASSA_PSS_PARAMS_SALT_LEN 6
180 #define RSASSA_PSS_PARAMS_TRAILER 8
181
182 /*
183 * Described in header
184 */
185 bool rsa_pss_params_parse(chunk_t asn1, int level0, rsa_pss_params_t *params)
186 {
187 asn1_parser_t *parser;
188 chunk_t object;
189 int objectID, alg;
190 bool success = FALSE;
191
192 params->hash = HASH_SHA1;
193 params->mgf1_hash = HASH_SHA1;
194 params->salt_len = HASH_SIZE_SHA1;
195
196 parser = asn1_parser_create(RSASSAPSSParamsObjects, asn1);
197 parser->set_top_level(parser, level0);
198
199 while (parser->iterate(parser, &objectID, &object))
200 {
201 u_int level = parser->get_level(parser)+1;
202
203 switch (objectID)
204 {
205 case RSASSA_PSS_PARAMS_HASH_ALG:
206 if (object.len)
207 {
208 alg = asn1_parse_algorithmIdentifier(object, level, NULL);
209 params->hash = hasher_algorithm_from_oid(alg);
210 if (params->hash == HASH_UNKNOWN)
211 {
212 goto end;
213 }
214 }
215 break;
216 case RSASSA_PSS_PARAMS_MGF_ALG:
217 if (object.len)
218 {
219 chunk_t hash;
220
221 alg = asn1_parse_algorithmIdentifier(object, level, &hash);
222 if (alg != OID_MGF1)
223 {
224 goto end;
225 }
226 alg = asn1_parse_algorithmIdentifier(hash, level+1, NULL);
227 params->mgf1_hash = hasher_algorithm_from_oid(alg);
228 if (params->mgf1_hash == HASH_UNKNOWN)
229 {
230 goto end;
231 }
232 }
233 break;
234 case RSASSA_PSS_PARAMS_SALT_LEN:
235 if (object.len)
236 {
237 params->salt_len = (size_t)asn1_parse_integer_uint64(object);
238 }
239 break;
240 case RSASSA_PSS_PARAMS_TRAILER:
241 if (object.len && (object.len != 1 || *object.ptr != 1))
242 {
243 goto end;
244 }
245 break;
246 default:
247 break;
248 }
249 }
250 success = parser->success(parser);
251
252 end:
253 parser->destroy(parser);
254 return success;
255 }
256
257 /*
258 * Described in header
259 */
260 bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
261 {
262 chunk_t hash = chunk_empty, mgf = chunk_empty, slen = chunk_empty;
263 ssize_t salt_len;
264 int alg;
265
266 if (params->hash != HASH_SHA1)
267 { /* with SHA-1 we MUST omit the field */
268 alg = hasher_algorithm_to_oid(params->hash);
269 if (alg == OID_UNKNOWN)
270 {
271 return FALSE;
272 }
273 hash = asn1_algorithmIdentifier(alg);
274 }
275 if (params->mgf1_hash != HASH_SHA1)
276 { /* with MGF1-SHA1 we MUST omit the field */
277 alg = hasher_algorithm_to_oid(params->mgf1_hash);
278 if (alg == OID_UNKNOWN)
279 {
280 chunk_free(&hash);
281 return FALSE;
282 }
283 mgf = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_MGF1),
284 asn1_algorithmIdentifier(alg));
285 }
286 salt_len = rsa_pss_salt_length(params);
287 if (salt_len < 0)
288 {
289 chunk_free(&hash);
290 chunk_free(&mgf);
291 return FALSE;
292 }
293 else if (salt_len != HASH_SIZE_SHA1)
294 {
295 slen = asn1_integer("m", asn1_integer_from_uint64(salt_len));
296 }
297 *asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm",
298 hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty,
299 mgf.len ? asn1_wrap(ASN1_CONTEXT_C_1, "m", mgf) : chunk_empty,
300 slen.len ? asn1_wrap(ASN1_CONTEXT_C_2, "m", slen) : chunk_empty);
301 return TRUE;
302 }