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-2025 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.5.2
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
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  ASN1_INC_POINTER(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 
187  //Write the corresponding ASN.1 tag
188  error = asn1InsertHeader(&tag, output, &n);
189  //Any error to report?
190  if(error)
191  return error;
192 
193  //Total number of bytes that have been written
194  *written = length + n;
195 
196  //Successful processing
197  return NO_ERROR;
198 }
199 
200 
201 /**
202  * @brief Format SignatureValue field
203  * @param[in] prngAlgo PRNG algorithm
204  * @param[in] prngContext Pointer to the PRNG context
205  * @param[in] tbsCert Pointer to the TBSCertificate to be signed
206  * @param[in] signAlgoId Signature algorithm identifier
207  * @param[in] publicKeyInfo Signer's public key information
208  * @param[in] privateKey Signer's private key
209  * @param[out] output Buffer where to format the ASN.1 structure
210  * @param[out] written Length of the resulting ASN.1 structure
211  * @return Error code
212  **/
213 
214 error_t x509FormatSignatureValue(const PrngAlgo *prngAlgo, void *prngContext,
215  const X509OctetString *tbsCert, const X509SignAlgoId *signAlgoId,
216  const X509SubjectPublicKeyInfo *publicKeyInfo, const void *privateKey,
217  uint8_t *output, size_t *written)
218 {
219  error_t error;
220  size_t n;
221  uint8_t *p;
222  Asn1Tag tag;
223 
224  //Point to the buffer where to write the ASN.1 structure
225  p = output;
226 
227  //If the output parameter is NULL, then the function calculates the length
228  //of the ASN.1 structure without copying any data
229  if(p != NULL)
230  {
231  //The bit string shall contain an initial octet which encodes the number
232  //of unused bits in the final subsequent octet
233  p[0] = 0;
234 
235  //Advance data pointer
236  p++;
237  }
238 
239  //The ASN.1 DER-encoded tbsCertificate is used as the input to the signature
240  //function
241  error = x509GenerateSignature(prngAlgo, prngContext, tbsCert, signAlgoId,
242  privateKey, p, &n);
243  //Any error to report?
244  if(error)
245  return error;
246 
247  //The signature is encapsulated within a bit string
248  tag.constructed = FALSE;
251  tag.length = n + 1;
252 
253  //Write the corresponding ASN.1 tag
254  error = asn1InsertHeader(&tag, output, &n);
255  //Any error to report?
256  if(error)
257  return error;
258 
259  //Total number of bytes that have been written
260  *written = tag.totalLength;
261 
262  //Successful processing
263  return NO_ERROR;
264 }
265 
266 
267 /**
268  * @brief Format RSASSA-PSS parameters
269  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
270  * @param[out] output Buffer where to format the ASN.1 structure
271  * @param[out] written Length of the resulting ASN.1 structure
272  * @return Error code
273  **/
274 
276  uint8_t *output, size_t *written)
277 {
278  error_t error;
279  size_t n;
280  size_t length;
281  uint8_t *p;
282  Asn1Tag tag;
283 
284  //Point to the buffer where to write the ASN.1 structure
285  p = output;
286  //Length of the ASN.1 structure
287  length = 0;
288 
289  //Format hashAlgorithm parameter
290  error = x509FormatRsaPssHashAlgo(rsaPssParams, p, &n);
291  //Any error to report?
292  if(error)
293  return error;
294 
295  //Advance data pointer
296  ASN1_INC_POINTER(p, n);
297  length += n;
298 
299  //Format maskGenAlgorithm parameter
300  error = x509FormatRsaPssMaskGenAlgo(rsaPssParams, p, &n);
301  //Any error to report?
302  if(error)
303  return error;
304 
305  //Advance data pointer
306  ASN1_INC_POINTER(p, n);
307  length += n;
308 
309  //Format saltLength parameter
310  error = x509FormatRsaPssSaltLength(rsaPssParams, p, &n);
311  //Any error to report?
312  if(error)
313  return error;
314 
315  //Advance data pointer
316  ASN1_INC_POINTER(p, n);
317  length += n;
318 
319  //The RSASSA-PSS parameters are encapsulated within a sequence
320  tag.constructed = TRUE;
323  tag.length = length;
324 
325  //Write the corresponding ASN.1 tag
326  error = asn1InsertHeader(&tag, output, &n);
327  //Any error to report?
328  if(error)
329  return error;
330 
331  //Total number of bytes that have been written
332  *written = tag.totalLength;
333 
334  //Successful processing
335  return NO_ERROR;
336 }
337 
338 
339 /**
340  * @brief Format RSASSA-PSS hash algorithm
341  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
342  * @param[out] output Buffer where to format the ASN.1 structure
343  * @param[out] written Length of the resulting ASN.1 structure
344  * @return Error code
345  **/
346 
348  uint8_t *output, size_t *written)
349 {
350  error_t error;
351  size_t n;
352  Asn1Tag tag;
353 
354  //Length of the ASN.1 structure
355  n = 0;
356 
357  //The default hash algorithm is SHA-1
358  if(rsaPssParams->hashAlgo.value != NULL &&
359  rsaPssParams->hashAlgo.length > 0)
360  {
361  //Write the hash algorithm identifier
362  tag.constructed = FALSE;
365  tag.length = rsaPssParams->hashAlgo.length;
366  tag.value = rsaPssParams->hashAlgo.value;
367 
368  //Write the corresponding ASN.1 tag
369  error = asn1WriteTag(&tag, FALSE, output, &n);
370  //Any error to report?
371  if(error)
372  return error;
373 
374  //The hashAlgorithm parameter is encapsulated within a sequence
375  tag.constructed = TRUE;
378  tag.length = n;
379 
380  //Write the corresponding ASN.1 tag
381  error = asn1InsertHeader(&tag, output, &n);
382  //Any error to report?
383  if(error)
384  return error;
385 
386  //Get the length of the resulting sequence
387  n = tag.totalLength;
388 
389  //Explicit tagging shall be used to encode each parameter
390  tag.constructed = TRUE;
392  tag.objType = 0;
393  tag.length = n;
394 
395  //Write the corresponding ASN.1 tag
396  error = asn1InsertHeader(&tag, output, &n);
397  //Any error to report?
398  if(error)
399  return error;
400 
401  //Get the length of the resulting tag
402  n = tag.totalLength;
403  }
404 
405  //Total number of bytes that have been written
406  *written = n;
407 
408  //Successful processing
409  return NO_ERROR;
410 }
411 
412 
413 /**
414  * @brief Format RSASSA-PSS mask generation algorithm
415  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
416  * @param[out] output Buffer where to format the ASN.1 structure
417  * @param[out] written Length of the resulting ASN.1 structure
418  * @return Error code
419  **/
420 
422  uint8_t *output, size_t *written)
423 {
424  error_t error;
425  size_t n;
426  size_t length;
427  uint8_t *p;
428  Asn1Tag tag;
429 
430  //Point to the buffer where to write the ASN.1 structure
431  p = output;
432  //Length of the ASN.1 structure
433  length = 0;
434 
435  //The default mask generation function is MGF1
436  if(rsaPssParams->maskGenAlgo.value != NULL &&
437  rsaPssParams->maskGenAlgo.length > 0)
438  {
439  //Write the mask generation algorithm identifier
440  tag.constructed = FALSE;
443  tag.length = rsaPssParams->maskGenAlgo.length;
444  tag.value = rsaPssParams->maskGenAlgo.value;
445 
446  //Write the corresponding ASN.1 tag
447  error = asn1WriteTag(&tag, FALSE, p, &n);
448  //Any error to report?
449  if(error)
450  return error;
451 
452  //Advance data pointer
453  ASN1_INC_POINTER(p, n);
454  length += n;
455 
456  //Write the algorithm identifier of the one-way hash function employed
457  //with the mask generation function
458  error = x509FormatRsaPssMaskGenHashAlgo(rsaPssParams, p, &n);
459  //Any error to report?
460  if(error)
461  return error;
462 
463  //Advance data pointer
464  ASN1_INC_POINTER(p, n);
465  length += n;
466 
467  //The maskGenAlgorithm parameter is encapsulated within a sequence
468  tag.constructed = TRUE;
471  tag.length = length;
472 
473  //Write the corresponding ASN.1 tag
474  error = asn1InsertHeader(&tag, output, &n);
475  //Any error to report?
476  if(error)
477  return error;
478 
479  //Get the length of the resulting sequence
480  n = tag.totalLength;
481 
482  //Explicit tagging shall be used to encode each parameter
483  tag.constructed = TRUE;
485  tag.objType = 1;
486  tag.length = n;
487 
488  //Write the corresponding ASN.1 tag
489  error = asn1InsertHeader(&tag, output, &n);
490  //Any error to report?
491  if(error)
492  return error;
493 
494  //Get the length of the resulting tag
495  length = tag.totalLength;
496  }
497 
498  //Total number of bytes that have been written
499  *written = length;
500 
501  //Successful processing
502  return NO_ERROR;
503 }
504 
505 
506 /**
507  * @brief Format RSASSA-PSS mask generation hash algorithm
508  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
509  * @param[out] output Buffer where to format the ASN.1 structure
510  * @param[out] written Length of the resulting ASN.1 structure
511  * @return Error code
512  **/
513 
515  uint8_t *output, size_t *written)
516 {
517  error_t error;
518  size_t n;
519  Asn1Tag tag;
520 
521  //Length of the ASN.1 structure
522  n = 0;
523 
524  //The default hash algorithm is SHA-1
525  if(rsaPssParams->maskGenHashAlgo.value != NULL &&
526  rsaPssParams->maskGenHashAlgo.length > 0)
527  {
528  //Write the algorithm identifier of the one-way hash function employed
529  //with the mask generation function
530  tag.constructed = FALSE;
533  tag.length = rsaPssParams->maskGenHashAlgo.length;
534  tag.value = rsaPssParams->maskGenHashAlgo.value;
535 
536  //Write the corresponding ASN.1 tag
537  error = asn1WriteTag(&tag, FALSE, output, &n);
538  //Any error to report?
539  if(error)
540  return error;
541 
542  //The hash algorithm identifier is encapsulated within a sequence
543  tag.constructed = TRUE;
546  tag.length = n;
547 
548  //Write the corresponding ASN.1 tag
549  error = asn1InsertHeader(&tag, output, &n);
550  //Any error to report?
551  if(error)
552  return error;
553 
554  //Get the length of the resulting sequence
555  n = tag.totalLength;
556  }
557 
558  //Total number of bytes that have been written
559  *written = n;
560 
561  //Successful processing
562  return NO_ERROR;
563 }
564 
565 
566 /**
567  * @brief Format RSASSA-PSS salt length
568  * @param[in] rsaPssParams Pointer to the RSA-PSS parameters
569  * @param[out] output Buffer where to format the ASN.1 structure
570  * @param[out] written Length of the resulting ASN.1 structure
571  * @return Error code
572  **/
573 
575  uint8_t *output, size_t *written)
576 {
577  error_t error;
578  size_t n;
579  Asn1Tag tag;
580 
581  //Length of the ASN.1 structure
582  n = 0;
583 
584  //The default length of the salt is 20
585  if(rsaPssParams->saltLen != 20)
586  {
587  //Write the length of the salt
588  error = asn1WriteInt32((int32_t) rsaPssParams->saltLen, FALSE, output, &n);
589  //Any error to report?
590  if(error)
591  return error;
592 
593  //Explicit tagging shall be used to encode the saltLength parameter
594  tag.constructed = TRUE;
596  tag.objType = 2;
597  tag.length = n;
598 
599  //Write the corresponding ASN.1 tag
600  error = asn1InsertHeader(&tag, output, &n);
601  //Any error to report?
602  if(error)
603  return error;
604 
605  //Get the length of the resulting tag
606  n = tag.totalLength;
607  }
608 
609  //Total number of bytes that have been written
610  *written = n;
611 
612  //Successful processing
613  return NO_ERROR;
614 }
615 
616 #endif
#define PrngAlgo
Definition: crypto.h:980
X509OctetString hashAlgo
Definition: x509_common.h:1076
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
error_t asn1InsertHeader(Asn1Tag *tag, uint8_t *data, size_t *written)
Insert an ASN.1 tag header.
Definition: asn1.c:643
error_t x509FormatRsaPssSaltLength(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS salt length.
X509OctetString maskGenHashAlgo
Definition: x509_common.h:1078
error_t x509GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const X509OctetString *tbsData, const X509SignAlgoId *signAlgoId, const void *privateKey, uint8_t *output, size_t *written)
Signature generation.
size_t totalLength
Definition: asn1.h:111
size_t length
Definition: asn1.h:109
#define FALSE
Definition: os_port.h:46
X509SignatureAlgo
Signature algorithms.
Definition: x509_common.h:652
error_t
Error codes.
Definition: error.h:43
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
error_t x509FormatRsaPssHashAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS hash algorithm.
ASN.1 tag.
Definition: asn1.h:105
#define ASN1_INC_POINTER(p, n)
Definition: asn1.h:58
@ X509_SIGN_ALGO_ECDSA
Definition: x509_common.h:657
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 x509FormatRsaPssMaskGenAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS mask generation algorithm.
General definitions for cryptographic algorithms.
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:408
error_t x509FormatRsaPssMaskGenHashAlgo(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS mask generation hash algorithm.
error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag.
Definition: asn1.c:334
error_t x509FormatSignatureAlgo(const X509SignAlgoId *signatureAlgo, uint8_t *output, size_t *written)
Format SignatureAlgorithm structure.
uint_t objClass
Definition: asn1.h:107
uint8_t length
Definition: tcp.h:375
X509OctetString oid
Definition: x509_common.h:1089
X509OctetString maskGenAlgo
Definition: x509_common.h:1077
@ X509_SIGN_ALGO_RSA
Definition: x509_common.h:654
RSA/DSA/ECDSA/EdDSA signature generation.
@ X509_SIGN_ALGO_RSA_PSS
Definition: x509_common.h:655
uint8_t n
Subject Public Key Information extension.
Definition: x509_common.h:838
#define ASN1_CLASS_CONTEXT_SPECIFIC
Definition: asn1.h:54
bool_t constructed
Definition: asn1.h:106
RSASSA-PSS parameters.
Definition: x509_common.h:1075
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:77
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:83
const uint8_t * value
Definition: x509_common.h:702
Common interface for hash algorithms.
Definition: crypto.h:1089
@ ASN1_TYPE_BIT_STRING
Definition: asn1.h:74
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
@ X509_SIGN_ALGO_SM2
Definition: x509_common.h:658
Octet string.
Definition: x509_common.h:701
@ X509_SIGN_ALGO_ED25519
Definition: x509_common.h:659
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:781
X509RsaPssParameters rsaPssParams
Definition: x509_common.h:1091
const uint8_t * value
Definition: asn1.h:110
Signature algorithm identifier.
Definition: x509_common.h:1088
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t objType
Definition: asn1.h:108
error_t x509FormatRsaPssParameters(const X509RsaPssParameters *rsaPssParams, uint8_t *output, size_t *written)
Format RSASSA-PSS parameters.
ASN.1 (Abstract Syntax Notation One)
@ X509_SIGN_ALGO_DSA
Definition: x509_common.h:656
@ X509_SIGN_ALGO_ED448
Definition: x509_common.h:660
@ ASN1_TYPE_NULL
Definition: asn1.h:76