x509_sign_parse.c
Go to the documentation of this file.
1 /**
2  * @file x509_signature_parse.c
3  * @brief RSA/DSA/ECDSA/EdDSA signature parsing
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "pkix/x509_sign_parse.h"
37 #include "encoding/asn1.h"
38 #include "debug.h"
39 
40 //Check crypto library configuration
41 #if (X509_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Parse SignatureAlgorithm structure
46  * @param[in] data Pointer to the ASN.1 structure to parse
47  * @param[in] length Length of the ASN.1 structure
48  * @param[out] totalLength Number of bytes that have been parsed
49  * @param[out] signatureAlgo Information resulting from the parsing process
50  * @return Error code
51  **/
52 
53 error_t x509ParseSignatureAlgo(const uint8_t *data, size_t length,
54  size_t *totalLength, X509SignAlgoId *signatureAlgo)
55 {
56  error_t error;
57  Asn1Tag tag;
58 
59  //Debug message
60  TRACE_DEBUG(" Parsing SignatureAlgorithm...\r\n");
61 
62  //Read the contents of the SignatureAlgorithm structure
63  error = asn1ReadSequence(data, length, &tag);
64  //Failed to decode ASN.1 tag?
65  if(error)
66  return error;
67 
68  //Save the total length of the field
69  *totalLength = tag.totalLength;
70 
71  //Point to the first field of the sequence
72  data = tag.value;
73  length = tag.length;
74 
75  //Read the signature algorithm identifier
76  error = asn1ReadOid(data, length, &tag);
77  //Failed to decode ASN.1 tag?
78  if(error)
79  return error;
80 
81  //Save the signature algorithm identifier
82  signatureAlgo->oid.value = tag.value;
83  signatureAlgo->oid.length = tag.length;
84 
85  //Point to the next field (if any)
86  data += tag.totalLength;
87  length -= tag.totalLength;
88 
89 #if (X509_RSA_PSS_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
90  //RSASSA-PSS algorithm identifier?
91  if(!asn1CheckOid(&tag, RSASSA_PSS_OID, sizeof(RSASSA_PSS_OID)))
92  {
93  //Read RSASSA-PSS parameters
95  &signatureAlgo->rsaPssParams);
96  }
97  else
98 #endif
99  //Unknown algorithm identifier?
100  {
101  //The parameters are optional
102  error = NO_ERROR;
103  }
104 
105  //Return status code
106  return error;
107 }
108 
109 
110 /**
111  * @brief Parse SignatureValue field
112  * @param[in] data Pointer to the ASN.1 structure to parse
113  * @param[in] length Length of the ASN.1 structure
114  * @param[out] totalLength Number of bytes that have been parsed
115  * @param[out] signature Information resulting from the parsing process
116  * @return Error code
117  **/
118 
120  size_t *totalLength, X509OctetString *signature)
121 {
122  error_t error;
123  Asn1Tag tag;
124 
125  //Debug message
126  TRACE_DEBUG(" Parsing SignatureValue...\r\n");
127 
128  //Read the contents of the SignatureValue structure
129  error = asn1ReadTag(data, length, &tag);
130  //Failed to decode ASN.1 tag?
131  if(error)
132  return error;
133 
134  //Save the total length of the field
135  *totalLength = tag.totalLength;
136 
137  //Enforce encoding, class and type
138  error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL,
140  //Invalid tag?
141  if(error)
142  return error;
143 
144  //The bit string shall contain an initial octet which encodes the number
145  //of unused bits in the final subsequent octet
146  if(tag.length < 1 || tag.value[0] != 0x00)
147  return ERROR_FAILURE;
148 
149  //Get the signature value
150  signature->value = tag.value + 1;
151  signature->length = tag.length - 1;
152 
153  //Successful processing
154  return NO_ERROR;
155 }
156 
157 
158 /**
159  * @brief Parse RSASSA-PSS parameters
160  * @param[in] data Pointer to the ASN.1 structure to parse
161  * @param[in] length Length of the ASN.1 structure
162  * @param[out] rsaPssParams Information resulting from the parsing process
163  * @return Error code
164  **/
165 
167  X509RsaPssParameters *rsaPssParams)
168 {
169  error_t error;
170  Asn1Tag tag;
171 
172  //Clear RSASSA-PSS parameters
173  osMemset(rsaPssParams, 0, sizeof(X509RsaPssParameters));
174 
175 #if (SHA1_SUPPORT == ENABLED)
176  //The default hash algorithm is SHA-1 (refer to RFC 4055, section 3.1)
177  rsaPssParams->hashAlgo.value = SHA1_OID;
178  rsaPssParams->hashAlgo.length = sizeof(SHA1_OID);
179 #endif
180 
181 #if (RSA_SUPPORT == ENABLED)
182  //The default mask generation function is MGF1 with SHA-1
183  rsaPssParams->maskGenAlgo.value = MGF1_OID;
184  rsaPssParams->maskGenAlgo.length = sizeof(MGF1_OID);
185 #endif
186 
187 #if (SHA1_SUPPORT == ENABLED)
188  //MGF1 requires a one-way hash function that is identified in the
189  //parameters field of the MGF1 algorithm identifier
190  rsaPssParams->maskGenHashAlgo.value = SHA1_OID;
191  rsaPssParams->maskGenHashAlgo.length = sizeof(SHA1_OID);
192 #endif
193 
194  //The default length of the salt is 20
195  rsaPssParams->saltLen = 20;
196 
197  //Read the contents of the structure
198  error = asn1ReadSequence(data, length, &tag);
199  //Failed to decode ASN.1 tag?
200  if(error)
201  return error;
202 
203  //Point to the first field of the sequence
204  data = tag.value;
205  length = tag.length;
206 
207  //Parse RSASSA-PSS parameters
208  while(length > 0)
209  {
210  //Read current parameter
211  error = asn1ReadTag(data, length, &tag);
212  //Failed to decode ASN.1 tag?
213  if(error)
214  return error;
215 
216  //The tags in this sequence are explicit
218  {
219  //Parse hashAlgorithm parameter
220  error = x509ParseRsaPssHashAlgo(tag.value, tag.length,
221  rsaPssParams);
222  }
223  else if(!asn1CheckTag(&tag, TRUE, ASN1_CLASS_CONTEXT_SPECIFIC, 1))
224  {
225  //Parse maskGenAlgorithm parameter
226  error = x509ParseRsaPssMaskGenAlgo(tag.value, tag.length,
227  rsaPssParams);
228  }
229  else if(!asn1CheckTag(&tag, TRUE, ASN1_CLASS_CONTEXT_SPECIFIC, 2))
230  {
231  //Parse saltLength parameter
232  error = x509ParseRsaPssSaltLength(tag.value, tag.length,
233  rsaPssParams);
234  }
235  else
236  {
237  //Discard current parameter
238  error = NO_ERROR;
239  }
240 
241  //Any parsing error?
242  if(error)
243  return error;
244 
245  //Next parameter
246  data += tag.totalLength;
247  length -= tag.totalLength;
248  }
249 
250  //Successful processing
251  return NO_ERROR;
252 }
253 
254 
255 /**
256  * @brief Parse RSASSA-PSS hash algorithm
257  * @param[in] data Pointer to the ASN.1 structure to parse
258  * @param[in] length Length of the ASN.1 structure
259  * @param[out] rsaPssParams Information resulting from the parsing process
260  * @return Error code
261  **/
262 
264  X509RsaPssParameters *rsaPssParams)
265 {
266  error_t error;
267  Asn1Tag tag;
268 
269  //Read the contents of the structure
270  error = asn1ReadSequence(data, length, &tag);
271  //Failed to decode ASN.1 tag?
272  if(error)
273  return error;
274 
275  //Point to the first field of the sequence
276  data = tag.value;
277  length = tag.length;
278 
279  //Read hash algorithm identifier
280  error = asn1ReadOid(data, length, &tag);
281  //Failed to decode ASN.1 tag?
282  if(error)
283  return error;
284 
285  //Save the hash algorithm identifier
286  rsaPssParams->hashAlgo.value = tag.value;
287  rsaPssParams->hashAlgo.length = tag.length;
288 
289  //No error to report
290  return NO_ERROR;
291 }
292 
293 
294 /**
295  * @brief Parse RSASSA-PSS mask generation algorithm
296  * @param[in] data Pointer to the ASN.1 structure to parse
297  * @param[in] length Length of the ASN.1 structure
298  * @param[out] rsaPssParams Information resulting from the parsing process
299  * @return Error code
300  **/
301 
303  X509RsaPssParameters *rsaPssParams)
304 {
305  error_t error;
306  Asn1Tag tag;
307 
308  //Read the contents of the structure
309  error = asn1ReadSequence(data, length, &tag);
310  //Failed to decode ASN.1 tag?
311  if(error)
312  return error;
313 
314  //Point to the first field of the sequence
315  data = tag.value;
316  length = tag.length;
317 
318  //Read mask generation algorithm identifier
319  error = asn1ReadOid(data, length, &tag);
320  //Failed to decode ASN.1 tag?
321  if(error)
322  return error;
323 
324  //Save the mask generation algorithm identifier
325  rsaPssParams->maskGenAlgo.value = tag.value;
326  rsaPssParams->maskGenAlgo.length = tag.length;
327 
328  //Point to the next field
329  data += tag.totalLength;
330  length -= tag.totalLength;
331 
332  //Read the algorithm identifier of the one-way hash function employed
333  //with the mask generation function
334  error = x509ParseRsaPssMaskGenHashAlgo(data, length, rsaPssParams);
335  //Any error to report?
336  if(error)
337  return error;
338 
339  //No error to report
340  return NO_ERROR;
341 }
342 
343 
344 /**
345  * @brief Parse RSASSA-PSS mask generation hash algorithm
346  * @param[in] data Pointer to the ASN.1 structure to parse
347  * @param[in] length Length of the ASN.1 structure
348  * @param[out] rsaPssParams Information resulting from the parsing process
349  * @return Error code
350  **/
351 
353  X509RsaPssParameters *rsaPssParams)
354 {
355  error_t error;
356  Asn1Tag tag;
357 
358  //Read the contents of the structure
359  error = asn1ReadSequence(data, length, &tag);
360  //Failed to decode ASN.1 tag?
361  if(error)
362  return error;
363 
364  //Point to the first field of the sequence
365  data = tag.value;
366  length = tag.length;
367 
368  //Read the algorithm identifier of the one-way hash function employed
369  //with the mask generation function
370  error = asn1ReadOid(data, length, &tag);
371  //Failed to decode ASN.1 tag?
372  if(error)
373  return error;
374 
375  //Save the hash algorithm identifier
376  rsaPssParams->maskGenHashAlgo.value = tag.value;
377  rsaPssParams->maskGenHashAlgo.length = tag.length;
378 
379  //No error to report
380  return NO_ERROR;
381 }
382 
383 
384 /**
385  * @brief Parse RSASSA-PSS salt length
386  * @param[in] data Pointer to the ASN.1 structure to parse
387  * @param[in] length Length of the ASN.1 structure
388  * @param[out] rsaPssParams Information resulting from the parsing process
389  * @return Error code
390  **/
391 
393  X509RsaPssParameters *rsaPssParams)
394 {
395  error_t error;
396  int32_t saltLen;
397  Asn1Tag tag;
398 
399  //Read the saltLength field
400  error = asn1ReadInt32(data, length, &tag, &saltLen);
401  //Failed to decode ASN.1 tag?
402  if(error)
403  return error;
404 
405  //Sanity check
406  if(saltLen < 0)
407  return ERROR_INVALID_SYNTAX;
408 
409  //Save the length of the salt
410  rsaPssParams->saltLen = (size_t) saltLen;
411 
412  //No error to report
413  return NO_ERROR;
414 }
415 
416 #endif
error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 tag from the input stream.
Definition: asn1.c:52
error_t asn1CheckOid(const Asn1Tag *tag, const uint8_t *oid, size_t length)
Check ASN.1 tag against a specified OID.
Definition: asn1.c:679
error_t asn1ReadSequence(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 sequence from the input stream.
Definition: asn1.c:163
error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass, uint_t objType)
Enforce the type of a specified tag.
Definition: asn1.c:653
error_t asn1ReadOid(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an object identifier from the input stream.
Definition: asn1.c:218
error_t asn1ReadInt32(const uint8_t *data, size_t length, Asn1Tag *tag, int32_t *value)
Read a 32-bit integer from the input stream.
Definition: asn1.c:285
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_BIT_STRING
Definition: asn1.h:71
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
#define ASN1_CLASS_CONTEXT_SPECIFIC
Definition: asn1.h:54
General definitions for cryptographic algorithms.
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
uint8_t data[]
Definition: ethernet.h:222
uint16_t totalLength
Definition: ipv4.h:292
#define osMemset(p, value, length)
Definition: os_port.h:135
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
const uint8_t MGF1_OID[9]
Definition: rsa.c:91
const uint8_t RSASSA_PSS_OID[9]
Definition: rsa.c:88
const uint8_t SHA1_OID[5]
Definition: sha1.c:73
ASN.1 tag.
Definition: asn1.h:102
size_t totalLength
Definition: asn1.h:108
const uint8_t * value
Definition: asn1.h:107
size_t length
Definition: asn1.h:106
Octet string.
Definition: x509_common.h:646
const uint8_t * value
Definition: x509_common.h:647
RSASSA-PSS parameters.
Definition: x509_common.h:1020
X509OctetString maskGenHashAlgo
Definition: x509_common.h:1023
X509OctetString hashAlgo
Definition: x509_common.h:1021
X509OctetString maskGenAlgo
Definition: x509_common.h:1022
Signature algorithm identifier.
Definition: x509_common.h:1033
X509OctetString oid
Definition: x509_common.h:1034
X509RsaPssParameters rsaPssParams
Definition: x509_common.h:1036
uint8_t length
Definition: tcp.h:368
error_t x509ParseRsaPssMaskGenHashAlgo(const uint8_t *data, size_t length, X509RsaPssParameters *rsaPssParams)
Parse RSASSA-PSS mask generation hash algorithm.
error_t x509ParseRsaPssHashAlgo(const uint8_t *data, size_t length, X509RsaPssParameters *rsaPssParams)
Parse RSASSA-PSS hash algorithm.
error_t x509ParseSignatureValue(const uint8_t *data, size_t length, size_t *totalLength, X509OctetString *signature)
Parse SignatureValue field.
error_t x509ParseRsaPssMaskGenAlgo(const uint8_t *data, size_t length, X509RsaPssParameters *rsaPssParams)
Parse RSASSA-PSS mask generation algorithm.
error_t x509ParseRsaPssSaltLength(const uint8_t *data, size_t length, X509RsaPssParameters *rsaPssParams)
Parse RSASSA-PSS salt length.
error_t x509ParseRsaPssParameters(const uint8_t *data, size_t length, X509RsaPssParameters *rsaPssParams)
Parse RSASSA-PSS parameters.
error_t x509ParseSignatureAlgo(const uint8_t *data, size_t length, size_t *totalLength, X509SignAlgoId *signatureAlgo)
Parse SignatureAlgorithm structure.