x509_sign_format.c
Go to the documentation of this file.
1 /**
2  * @file x509_signature_format.c
3  * @brief RSA/DSA/ECDSA/EdDSA signature formatting
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_format.h"
38 #include "encoding/asn1.h"
39 #include "debug.h"
40 
41 //Check crypto library configuration
42 #if (X509_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Format SignatureAlgorithm structure
47  * @param[in] signatureAlgo Pointer to the SignatureAlgorithm structure
48  * @param[out] output Buffer where to format the ASN.1 structure
49  * @param[out] written Length of the resulting ASN.1 structure
50  * @return Error code
51  **/
52 
54  uint8_t *output, size_t *written)
55 {
56  error_t error;
57  size_t n;
58  size_t length;
59  uint8_t *p;
60  Asn1Tag tag;
61  X509SignatureAlgo signAlgo;
62  const HashAlgo *hashAlgo;
63 
64  //Point to the buffer where to write the ASN.1 structure
65  p = output;
66  //Length of the ASN.1 structure
67  length = 0;
68 
69  //Retrieve the signature algorithm that will be used to sign the certificate
70  error = x509GetSignHashAlgo(signatureAlgo, &signAlgo, &hashAlgo);
71  //Unsupported signature algorithm?
72  if(error)
73  return error;
74 
75  //The Algorithm field contains the OID for the algorithm used by the CA
76  //to sign the certificate
77  tag.constructed = FALSE;
80  tag.length = signatureAlgo->oid.length;
81  tag.value = signatureAlgo->oid.value;
82 
83  //Write the corresponding ASN.1 tag
84  error = asn1WriteTag(&tag, FALSE, p, &n);
85  //Any error to report?
86  if(error)
87  return error;
88 
89  //Advance data pointer
90  p += n;
91  length += n;
92 
93 #if (X509_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
94  //RSA signature algorithm?
95  if(signAlgo == X509_SIGN_ALGO_RSA)
96  {
97  //For RSA signature algorithm, the parameters component of that type
98  //shall be the ASN.1 type NULL (refer to RFC 3279, section 2.2.1)
99  tag.constructed = FALSE;
101  tag.objType = ASN1_TYPE_NULL;
102  tag.length = 0;
103  tag.value = NULL;
104 
105  //Write the corresponding ASN.1 tag
106  error = asn1WriteTag(&tag, FALSE, p, &n);
107  }
108  else
109 #endif
110 #if (X509_RSA_PSS_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
111  //RSA-PSS signature algorithm?
112  if(signAlgo == X509_SIGN_ALGO_RSA_PSS)
113  {
114  //The parameters must be present when used in the algorithm identifier
115  //associated with a signature value (refer to RFC 4055, section 3.1)
116  error = x509FormatRsaPssParameters(&signatureAlgo->rsaPssParams, p, &n);
117  }
118  else
119 #endif
120 #if (X509_DSA_SUPPORT == ENABLED && DSA_SUPPORT == ENABLED)
121  //DSA signature algorithm?
122  if(signAlgo == X509_SIGN_ALGO_DSA)
123  {
124  //For DSA signature algorithm, the encoding shall omit the parameters
125  //field (refer to RFC 3279, section 2.2.2)
126  n = 0;
127  }
128  else
129 #endif
130 #if (X509_ECDSA_SUPPORT == ENABLED && ECDSA_SUPPORT == ENABLED)
131  //ECDSA signature algorithm?
132  if(signAlgo == X509_SIGN_ALGO_ECDSA)
133  {
134  //For ECDSA signature algorithm, the encoding must omit the parameters
135  //field (refer to RFC 3279, section 2.2.3)
136  n = 0;
137  }
138  else
139 #endif
140 #if (X509_SM2_SUPPORT == ENABLED && SM2_SUPPORT == ENABLED)
141  //SM2 signature algorithm?
142  if(signAlgo == X509_SIGN_ALGO_SM2)
143  {
144  //If the signature algorithm is SM2, no parameters are involved
145  n = 0;
146  }
147  else
148 #endif
149 #if (X509_ED25519_SUPPORT == ENABLED && ED25519_SUPPORT == ENABLED)
150  //Ed25519 signature algorithm?
151  if(signAlgo == X509_SIGN_ALGO_ED25519)
152  {
153  //The parameters must be absent (refer to RFC 8410, section 6)
154  n = 0;
155  }
156  else
157 #endif
158 #if (X509_ED448_SUPPORT == ENABLED && ED448_SUPPORT == ENABLED)
159  //Ed448 signature algorithm?
160  if(signAlgo == X509_SIGN_ALGO_ED448)
161  {
162  //The parameters must be absent (refer to RFC 8410, section 6)
163  n = 0;
164  }
165  else
166 #endif
167  //Invalid signature algorithm?
168  {
169  //Report an error
171  }
172 
173  //Check status code
174  if(error)
175  return error;
176 
177  //Advance data pointer
178  p += n;
179  length += n;
180 
181  //The Algorithm and Parameters fields are encapsulated within a sequence
182  tag.constructed = TRUE;
185  tag.length = length;
186  tag.value = output;
187 
188  //Write the corresponding ASN.1 tag
189  error = asn1WriteTag(&tag, FALSE, output, &length);
190  //Any error to report?
191  if(error)
192  return error;
193 
194  //Total number of bytes that have been written
195  *written = length;
196 
197  //Successful processing
198  return NO_ERROR;
199 }
200 
201 
202 /**
203  * @brief Format SignatureValue field
204  * @param[in] prngAlgo PRNG algorithm
205  * @param[in] prngContext Pointer to the PRNG context
206  * @param[in] tbsCert Pointer to the TBSCertificate to be signed
207  * @param[in] signAlgoId Signature algorithm identifier
208  * @param[in] publicKeyInfo Signer's public key information
209  * @param[in] privateKey Signer's private key
210  * @param[out] output Buffer where to format the ASN.1 structure
211  * @param[out] written Length of the resulting ASN.1 structure
212  * @return Error code
213  **/
214 
215 error_t x509FormatSignatureValue(const PrngAlgo *prngAlgo, void *prngContext,
216  const X509OctetString *tbsCert, const X509SignAlgoId *signAlgoId,
217  const X509SubjectPublicKeyInfo *publicKeyInfo, const void *privateKey,
218  uint8_t *output, size_t *written)
219 {
220  error_t error;
221  size_t n;
222  Asn1Tag tag;
223 
224  //The bit string shall contain an initial octet which encodes the number
225  //of unused bits in the final subsequent octet
226  output[0] = 0;
227 
228  //The ASN.1 DER-encoded tbsCertificate is used as the input to the signature
229  //function
230  error = x509GenerateSignature(prngAlgo, prngContext, tbsCert,
231  signAlgoId, publicKeyInfo, privateKey, output + 1, &n);
232  //Any error to report?
233  if(error)
234  return error;
235 
236  //The signature is encapsulated within a bit string
237  tag.constructed = FALSE;
240  tag.length = n + 1;
241  tag.value = output;
242 
243  //Write the corresponding ASN.1 tag
244  error = asn1WriteTag(&tag, FALSE, output, &n);
245  //Any error to report?
246  if(error)
247  return error;
248 
249  //Total number of bytes that have been written
250  *written = n;
251 
252  //Successful processing
253  return NO_ERROR;
254 }
255 
256 
257 /**
258  * @brief Format RSASSA-PSS parameters
259  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
260  * @param[out] output Buffer where to format the ASN.1 structure
261  * @param[out] written Length of the resulting ASN.1 structure
262  * @return Error code
263  **/
264 
266  uint8_t *output, size_t *written)
267 {
268  error_t error;
269  size_t n;
270  size_t length;
271  uint8_t *p;
272  Asn1Tag tag;
273 
274  //Point to the buffer where to write the ASN.1 structure
275  p = output;
276  //Length of the ASN.1 structure
277  length = 0;
278 
279  //Format hashAlgorithm parameter
280  error = x509FormatRsaPssHashAlgo(rsaPssParams, p, &n);
281  //Any error to report?
282  if(error)
283  return error;
284 
285  //Advance data pointer
286  p += n;
287  length += n;
288 
289  //Format maskGenAlgorithm parameter
290  error = x509FormatRsaPssMaskGenAlgo(rsaPssParams, p, &n);
291  //Any error to report?
292  if(error)
293  return error;
294 
295  //Advance data pointer
296  p += n;
297  length += n;
298 
299  //Format saltLength parameter
300  error = x509FormatRsaPssSaltLength(rsaPssParams, p, &n);
301  //Any error to report?
302  if(error)
303  return error;
304 
305  //Advance data pointer
306  p += n;
307  length += n;
308 
309  //The RSASSA-PSS parameters are encapsulated within a sequence
310  tag.constructed = TRUE;
313  tag.length = length;
314  tag.value = output;
315 
316  //Write the corresponding ASN.1 tag
317  error = asn1WriteTag(&tag, FALSE, output, &n);
318  //Any error to report?
319  if(error)
320  return error;
321 
322  //Total number of bytes that have been written
323  *written = n;
324 
325  //Successful processing
326  return NO_ERROR;
327 }
328 
329 
330 /**
331  * @brief Format RSASSA-PSS hash algorithm
332  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
333  * @param[out] output Buffer where to format the ASN.1 structure
334  * @param[out] written Length of the resulting ASN.1 structure
335  * @return Error code
336  **/
337 
339  uint8_t *output, size_t *written)
340 {
341  error_t error;
342  size_t n;
343  Asn1Tag tag;
344 
345  //Length of the ASN.1 structure
346  n = 0;
347 
348  //The default hash algorithm is SHA-1
349  if(rsaPssParams->hashAlgo.value != NULL &&
350  rsaPssParams->hashAlgo.length > 0)
351  {
352  //Write the hash algorithm identifier
353  tag.constructed = FALSE;
356  tag.length = rsaPssParams->hashAlgo.length;
357  tag.value = rsaPssParams->hashAlgo.value;
358 
359  //Write the corresponding ASN.1 tag
360  error = asn1WriteTag(&tag, FALSE, output, &n);
361  //Any error to report?
362  if(error)
363  return error;
364 
365  //The hashAlgorithm parameter is encapsulated within a sequence
366  tag.constructed = TRUE;
369  tag.length = n;
370  tag.value = output;
371 
372  //Write the corresponding ASN.1 tag
373  error = asn1WriteTag(&tag, FALSE, output, &n);
374  //Any error to report?
375  if(error)
376  return error;
377 
378  //Explicit tagging shall be used to encode each parameter
379  tag.constructed = TRUE;
381  tag.objType = 0;
382  tag.length = n;
383  tag.value = output;
384 
385  //Write the corresponding ASN.1 tag
386  error = asn1WriteTag(&tag, FALSE, output, &n);
387  //Any error to report?
388  if(error)
389  return error;
390  }
391 
392  //Total number of bytes that have been written
393  *written = n;
394 
395  //Successful processing
396  return NO_ERROR;
397 }
398 
399 
400 /**
401  * @brief Format RSASSA-PSS mask generation algorithm
402  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
403  * @param[out] output Buffer where to format the ASN.1 structure
404  * @param[out] written Length of the resulting ASN.1 structure
405  * @return Error code
406  **/
407 
409  uint8_t *output, size_t *written)
410 {
411  error_t error;
412  size_t n;
413  size_t length;
414  uint8_t *p;
415  Asn1Tag tag;
416 
417  //Point to the buffer where to write the ASN.1 structure
418  p = output;
419  //Length of the ASN.1 structure
420  length = 0;
421 
422  //The default mask generation function is MGF1
423  if(rsaPssParams->maskGenAlgo.value != NULL &&
424  rsaPssParams->maskGenAlgo.length > 0)
425  {
426  //Write the mask generation algorithm identifier
427  tag.constructed = FALSE;
430  tag.length = rsaPssParams->maskGenAlgo.length;
431  tag.value = rsaPssParams->maskGenAlgo.value;
432 
433  //Write the corresponding ASN.1 tag
434  error = asn1WriteTag(&tag, FALSE, p, &n);
435  //Any error to report?
436  if(error)
437  return error;
438 
439  //Advance data pointer
440  p += n;
441  length += n;
442 
443  //Write the algorithm identifier of the one-way hash function employed
444  //with the mask generation function
445  error = x509FormatRsaPssMaskGenHashAlgo(rsaPssParams, p, &n);
446  //Any error to report?
447  if(error)
448  return error;
449 
450  //Advance data pointer
451  p += n;
452  length += n;
453 
454  //The maskGenAlgorithm parameter is encapsulated within a sequence
455  tag.constructed = TRUE;
458  tag.length = length;
459  tag.value = output;
460 
461  //Write the corresponding ASN.1 tag
462  error = asn1WriteTag(&tag, FALSE, output, &length);
463  //Any error to report?
464  if(error)
465  return error;
466 
467  //Explicit tagging shall be used to encode each parameter
468  tag.constructed = TRUE;
470  tag.objType = 1;
471  tag.length = length;
472  tag.value = output;
473 
474  //Write the corresponding ASN.1 tag
475  error = asn1WriteTag(&tag, FALSE, output, &length);
476  //Any error to report?
477  if(error)
478  return error;
479  }
480 
481  //Total number of bytes that have been written
482  *written = length;
483 
484  //Successful processing
485  return NO_ERROR;
486 }
487 
488 
489 /**
490  * @brief Format RSASSA-PSS mask generation hash algorithm
491  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
492  * @param[out] output Buffer where to format the ASN.1 structure
493  * @param[out] written Length of the resulting ASN.1 structure
494  * @return Error code
495  **/
496 
498  uint8_t *output, size_t *written)
499 {
500  error_t error;
501  size_t n;
502  Asn1Tag tag;
503 
504  //Length of the ASN.1 structure
505  n = 0;
506 
507  //The default hash algorithm is SHA-1
508  if(rsaPssParams->maskGenHashAlgo.value != NULL &&
509  rsaPssParams->maskGenHashAlgo.length > 0)
510  {
511  //Write the algorithm identifier of the one-way hash function employed
512  //with the mask generation function
513  tag.constructed = FALSE;
516  tag.length = rsaPssParams->maskGenHashAlgo.length;
517  tag.value = rsaPssParams->maskGenHashAlgo.value;
518 
519  //Write the corresponding ASN.1 tag
520  error = asn1WriteTag(&tag, FALSE, output, &n);
521  //Any error to report?
522  if(error)
523  return error;
524 
525  //The hash algorithm identifier is encapsulated within a sequence
526  tag.constructed = TRUE;
529  tag.length = n;
530  tag.value = output;
531 
532  //Write the corresponding ASN.1 tag
533  error = asn1WriteTag(&tag, FALSE, output, &n);
534  //Any error to report?
535  if(error)
536  return error;
537  }
538 
539  //Total number of bytes that have been written
540  *written = n;
541 
542  //Successful processing
543  return NO_ERROR;
544 }
545 
546 
547 /**
548  * @brief Format RSASSA-PSS salt length
549  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
550  * @param[out] output Buffer where to format the ASN.1 structure
551  * @param[out] written Length of the resulting ASN.1 structure
552  * @return Error code
553  **/
554 
556  uint8_t *output, size_t *written)
557 {
558  error_t error;
559  size_t n;
560  Asn1Tag tag;
561 
562  //Length of the ASN.1 structure
563  n = 0;
564 
565  //The default length of the salt is 20
566  if(rsaPssParams->saltLen != 20)
567  {
568  //Write the length of the salt
569  error = asn1WriteInt32((int32_t) rsaPssParams->saltLen, FALSE, output, &n);
570  //Any error to report?
571  if(error)
572  return error;
573 
574  //Explicit tagging shall be used to encode the saltLength parameter
575  tag.constructed = TRUE;
577  tag.objType = 2;
578  tag.length = n;
579  tag.value = output;
580 
581  //Write the corresponding ASN.1 tag
582  error = asn1WriteTag(&tag, FALSE, output, &n);
583  //Any error to report?
584  if(error)
585  return error;
586  }
587 
588  //Total number of bytes that have been written
589  *written = n;
590 
591  //Successful processing
592  return NO_ERROR;
593 }
594 
595 #endif
error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data, size_t *written)
Write a 32-bit integer to the output stream.
Definition: asn1.c:495
error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag.
Definition: asn1.c:334
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:74
@ ASN1_TYPE_BIT_STRING
Definition: asn1.h:71
@ ASN1_TYPE_NULL
Definition: asn1.h:73
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:80
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
#define ASN1_CLASS_CONTEXT_SPECIFIC
Definition: asn1.h:54
General definitions for cryptographic algorithms.
#define PrngAlgo
Definition: crypto.h:917
Debugging facilities.
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
ASN.1 tag.
Definition: asn1.h:102
const uint8_t * value
Definition: asn1.h:107
uint_t objClass
Definition: asn1.h:104
uint_t objType
Definition: asn1.h:105
bool_t constructed
Definition: asn1.h:103
size_t length
Definition: asn1.h:106
Common interface for hash algorithms.
Definition: crypto.h:1014
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
Subject Public Key Information extension.
Definition: x509_common.h:783
uint8_t length
Definition: tcp.h:368
error_t x509GetSignHashAlgo(const X509SignAlgoId *signAlgoId, X509SignatureAlgo *signAlgo, const HashAlgo **hashAlgo)
Get the signature and hash algorithms that match the specified identifier.
Definition: x509_common.c:377
X509SignatureAlgo
Signature algorithms.
Definition: x509_common.h:597
@ X509_SIGN_ALGO_ED448
Definition: x509_common.h:605
@ X509_SIGN_ALGO_ED25519
Definition: x509_common.h:604
@ X509_SIGN_ALGO_SM2
Definition: x509_common.h:603
@ X509_SIGN_ALGO_RSA
Definition: x509_common.h:599
@ X509_SIGN_ALGO_DSA
Definition: x509_common.h:601
@ X509_SIGN_ALGO_ECDSA
Definition: x509_common.h:602
@ X509_SIGN_ALGO_RSA_PSS
Definition: x509_common.h:600
error_t x509FormatRsaPssSaltLength(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS salt length.
error_t x509FormatRsaPssMaskGenAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS mask generation algorithm.
error_t x509FormatSignatureValue(const PrngAlgo *prngAlgo, void *prngContext, const X509OctetString *tbsCert, const X509SignAlgoId *signAlgoId, const X509SubjectPublicKeyInfo *publicKeyInfo, const void *privateKey, uint8_t *output, size_t *written)
Format SignatureValue field.
error_t x509FormatRsaPssHashAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS hash algorithm.
error_t x509FormatRsaPssMaskGenHashAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS mask generation hash algorithm.
error_t x509FormatSignatureAlgo(const X509SignAlgoId *signatureAlgo, uint8_t *output, size_t *written)
Format SignatureAlgorithm structure.
error_t x509FormatRsaPssParameters(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS parameters.
error_t x509GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const X509OctetString *tbsData, const X509SignAlgoId *signAlgoId, const X509SubjectPublicKeyInfo *publicKeyInfo, const void *privateKey, uint8_t *output, size_t *written)
Certificate signature generation.
RSA/DSA/ECDSA/EdDSA signature generation.