pkcs7_sign_generate.c
Go to the documentation of this file.
1 /**
2  * @file pkcs7_sign_generate.c
3  * @brief PKCS #7 signature generation
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 "pkcs7/pkcs7_format.h"
38 #include "encoding/oid.h"
39 #include "debug.h"
40 
41 //Check crypto library configuration
42 #if (PKCS7_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Generate signed-data content
47  * @param[in] prngAlgo PRNG algorithm
48  * @param[in] prngContext Pointer to the PRNG context
49  * @param[in] content Pointer to the message to be signed
50  * @param[in] contentLen Length of the message, in bytes
51  * @param[in] signerCertInfo Signer's certificate
52  * @param[in] authenticatedAttributes Collection of attributes that are signed
53  * @param[in] unauthenticatedAttributes Collection of attributes that are not signed
54  * @param[in] signatureAlgo Signature algorithm
55  * @param[in] signerPrivateKey Pointer to the signer's private key
56  * @param[out] output Buffer where to format the ASN.1 structure
57  * @param[out] written Length of the resulting ASN.1 structure
58  * @return Error code
59  **/
60 
61 error_t pkcs7GenerateSignedData(const PrngAlgo *prngAlgo, void *prngContext,
62  const uint8_t *content, size_t contentLen, const X509CertInfo *signerCertInfo,
63  const Pkcs7AuthenticatedAttributes *authenticatedAttributes,
64  const Pkcs7UnauthenticatedAttributes *unauthenticatedAttributes,
65  const X509SignAlgoId *signatureAlgo, const void *signerPrivateKey,
66  uint8_t *output, size_t *written)
67 {
68  error_t error;
69  const HashAlgo *hashAlgo;
70  Pkcs7SignedData signedData;
71  uint8_t messageDigest[MAX_HASH_DIGEST_SIZE];
72 
73  //Get the signature hash algorithm
74  hashAlgo = pkcs7GetSignHashAlgo(signatureAlgo->oid.value,
75  signatureAlgo->oid.length);
76  //Invalid algorithm?
77  if(hashAlgo == NULL)
79 
80  //Only the contents octets of the DER encoding of that field are digested,
81  //not the identifier octets or the length octets (refer to RFC 2315,
82  //section 9.3)
83  error = hashAlgo->compute(content, contentLen, messageDigest);
84  //Any error to report?
85  if(error)
86  return error;
87 
88  //Clear SignedData structure
89  osMemset(&signedData, 0, sizeof(Pkcs7SignedData));
90 
91  //version is the syntax version number
92  signedData.version = PKCS7_VERSION_1;
93 
94  //digestAlgorithms is a collection of message-digest algorithm identifiers
95  signedData.digestAlgos.numIdentifiers = 1;
96  signedData.digestAlgos.identifiers[0].oid.value = hashAlgo->oid;
97  signedData.digestAlgos.identifiers[0].oid.length = hashAlgo->oidSize;
98 
99  //contentInfo is the content that is signed. It can have any of the defined
100  //content types
102  signedData.contentInfo.contentType.length = sizeof(PKCS7_DATA_OID);
103  signedData.contentInfo.content.value = content;
104  signedData.contentInfo.content.length = contentLen;
105 
106  //certificates is a set of PKCS #6 extended certificates and X.509
107  //certificates
108  signedData.certificates.numCertificates = 1;
109  signedData.certificates.certificates[0].value = signerCertInfo->raw.value;
110  signedData.certificates.certificates[0].length = signerCertInfo->raw.length;
111 
112  //crls is a set of certificate-revocation lists
113  signedData.crls.numCrls = 0;
114 
115  //signerInfos is a collection of per-signer information
116  signedData.signerInfos.numSignerInfos = 1;
118  signedData.signerInfos.signerInfos[0].issuerAndSerialNumber.name.raw = signerCertInfo->tbsCert.issuer.raw;
120  signedData.signerInfos.signerInfos[0].digestAlgo.oid.value = hashAlgo->oid;
121  signedData.signerInfos.signerInfos[0].digestAlgo.oid.length = hashAlgo->oidSize;
122 
123  //The authenticatedAttributes field is optional
124  if(authenticatedAttributes != NULL)
125  {
126  //authenticatedAttributes is a set of attributes that are signed by the
127  //signer
128  signedData.signerInfos.signerInfos[0].authenticatedAttributes = *authenticatedAttributes;
129  signedData.signerInfos.signerInfos[0].authenticatedAttributes.messageDigest.value = messageDigest;
131  }
132 
133  //The unauthenticatedAttributes field is optional
134  if(unauthenticatedAttributes != NULL)
135  {
136  //unauthenticatedAttributes is a set of attributes that are not signed by
137  //the signer
138  signedData.signerInfos.signerInfos[0].unauthenticatedAttributes = *unauthenticatedAttributes;
139  }
140 
141  //digestEncryptionAlgorithm identifies the digest-encryption algorithm under
142  //which the message digest and associated information are encrypted with the
143  //signer's private key (refer to RFC 2315, section 9.2)
144  signedData.signerInfos.signerInfos[0].digestEncryptionAlgo = *signatureAlgo;
145 
146  //Format signed-data content
147  error = pkcs7FormatSignedData(prngAlgo, prngContext, &signedData,
148  signerPrivateKey, output, written);
149 
150  //Return status code
151  return error;
152 }
153 
154 
155 /**
156  * @brief Signature generation
157  * @param[in] prngAlgo PRNG algorithm
158  * @param[in] prngContext Pointer to the PRNG context
159  * @param[in] digest Message digest
160  * @param[in] signerInfo Pointer to the signer information
161  * @param[in] privateKey Signer's private key
162  * @param[out] output Resulting signature
163  * @param[out] written Length of the resulting signature
164  * @return Error code
165  **/
166 
167 error_t pkcs7GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
168  const uint8_t *digest, const Pkcs7SignerInfo *signerInfo,
169  const void *privateKey, uint8_t *output, size_t *written)
170 {
171  error_t error;
172  size_t oidLen;
173  const uint8_t *oid;
174 
175  //Get the signature algorithm identifier
176  oid = signerInfo->digestEncryptionAlgo.oid.value;
177  oidLen = signerInfo->digestEncryptionAlgo.oid.length;
178 
179 #if (PKCS7_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
180  //RSA signature algorithm?
187  {
188  //Generate RSA signature (RSASSA-PKCS1-v1_5 signature scheme)
189  error = pkcs7GenerateRsaSignature(digest, signerInfo, privateKey,
190  output, written);
191  }
192  else
193 #endif
194  //Unknown signature algorithm?
195  {
196  //Report an error
198  }
199 
200  //Return status code
201  return error;
202 }
203 
204 
205 /**
206  * @brief RSA signature generation
207  * @param[in] digest Message digest
208  * @param[in] signerInfo Pointer to the signer information
209  * @param[in] privateKey Signer's private key
210  * @param[out] output Resulting signature
211  * @param[out] written Length of the resulting signature
212  * @return Error code
213  **/
214 
215 error_t pkcs7GenerateRsaSignature(const uint8_t *digest,
216  const Pkcs7SignerInfo *signerInfo, const RsaPrivateKey *privateKey,
217  uint8_t *output, size_t *written)
218 {
219 #if (X509_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
220  error_t error;
221  const HashAlgo *hashAlgo;
222 
223  //Initialize status code
224  error = NO_ERROR;
225 
226  //If the output parameter is NULL, then the function calculates the length
227  //of the resulting signature but will not generate a signature
228  if(output != NULL)
229  {
230  //The rsaEncryption algorithm identifier is used to identify RSA (PKCS #1
231  //v1.5) signature values regardless of the message digest algorithm
232  //employed (refer to RFC 3370, section 3.2)
233  if(OID_COMP(signerInfo->digestEncryptionAlgo.oid.value,
235  {
236  //CMS implementations that include the RSA (PKCS #1 v1.5) signature
237  //algorithm must support the rsaEncryption signature value algorithm
238  //identifier
239  hashAlgo = pkcs7GetHashAlgo(signerInfo->digestAlgo.oid.value,
240  signerInfo->digestAlgo.oid.length);
241  }
242  else
243  {
244  //CMS implementations may support RSA (PKCS #1 v1.5) signature value
245  //algorithm identifiers that specify both the RSA (PKCS #1 v1.5)
246  //signature algorithm and the message digest algorithm
247  hashAlgo = pkcs7GetSignHashAlgo(signerInfo->digestEncryptionAlgo.oid.value,
248  signerInfo->digestEncryptionAlgo.oid.length);
249  }
250 
251  //Valid hash algorithm?
252  if(hashAlgo != NULL)
253  {
254  //Generate RSA signature
255  error = rsassaPkcs1v15Sign(privateKey, hashAlgo, digest, output,
256  written);
257  }
258  else
259  {
260  //Report an error
262  }
263  }
264  else
265  {
266  //Length of the resulting RSA signature
267  *written = mpiGetByteLength(&privateKey->n);
268  }
269 
270  //Return status code
271  return error;
272 #else
273  //Not implemented
274  return ERROR_NOT_IMPLEMENTED;
275 #endif
276 }
277 
278 #endif
X509TbsCertificate tbsCert
Definition: x509_common.h:1121
const HashAlgo * pkcs7GetHashAlgo(const uint8_t *oid, size_t length)
Get the hash algorithm that matches the specified OID.
Definition: pkcs7_common.c:77
const uint8_t * oid
Definition: crypto.h:1091
X509SerialNumber serialNumber
Definition: pkcs7_common.h:216
const uint8_t MD5_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:59
const uint8_t SHA512_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:69
Pkcs7Certificates certificates
Definition: pkcs7_common.h:355
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
#define PrngAlgo
Definition: crypto.h:980
OID (Object Identifier)
Pkcs7AuthenticatedAttributes authenticatedAttributes
Definition: pkcs7_common.h:268
X509OctetString messageDigest
Definition: pkcs7_common.h:240
size_t digestSize
Definition: crypto.h:1095
Pkcs7ContentInfo contentInfo
Definition: pkcs7_common.h:354
Mpi n
Modulus.
Definition: rsa.h:69
X509OctetString certificates[PKCS7_MAX_CERTIFICATES]
Definition: pkcs7_common.h:193
Pkcs7Crls crls
Definition: pkcs7_common.h:356
Pkcs7UnauthenticatedAttributes unauthenticatedAttributes
Definition: pkcs7_common.h:271
uint8_t oid[]
Definition: lldp_tlv.h:300
size_t oidSize
Definition: crypto.h:1092
const uint8_t SHA384_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:67
#define MAX_HASH_DIGEST_SIZE
X509OctetString raw
Definition: x509_common.h:1120
X.509 certificate.
Definition: x509_common.h:1119
error_t
Error codes.
Definition: error.h:43
Signer information.
Definition: pkcs7_common.h:264
HashAlgoCompute compute
Definition: crypto.h:1098
X509OctetString contentType
Definition: pkcs7_common.h:318
X509AlgoId identifiers[PKCS7_MAX_DIGEST_ALGO_IDENTIFIERS]
Definition: pkcs7_common.h:181
X509OctetString oid
Definition: x509_common.h:775
General definitions for cryptographic algorithms.
X509SerialNumber serialNumber
Definition: x509_common.h:1104
uint_t numCrls
Definition: pkcs7_common.h:204
error_t pkcs7GenerateSignedData(const PrngAlgo *prngAlgo, void *prngContext, const uint8_t *content, size_t contentLen, const X509CertInfo *signerCertInfo, const Pkcs7AuthenticatedAttributes *authenticatedAttributes, const Pkcs7UnauthenticatedAttributes *unauthenticatedAttributes, const X509SignAlgoId *signatureAlgo, const void *signerPrivateKey, uint8_t *output, size_t *written)
Generate signed-data content.
Pkcs7DigestAlgos digestAlgos
Definition: pkcs7_common.h:353
X509OctetString oid
Definition: x509_common.h:1089
Pkcs7IssuerAndSerialNumber issuerAndSerialNumber
Definition: pkcs7_common.h:266
const uint8_t SHA256_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:65
const uint8_t RSA_ENCRYPTION_OID[9]
Definition: rsa.c:54
const HashAlgo * pkcs7GetSignHashAlgo(const uint8_t *oid, size_t length)
Get the signature hash algorithm that matches the specified OID.
Definition: pkcs7_common.c:146
const uint8_t PKCS7_DATA_OID[9]
Definition: pkcs7_common.c:50
Signed data content.
Definition: pkcs7_common.h:351
@ ERROR_INVALID_SIGNATURE_ALGO
Definition: error.h:135
X509AlgoId digestAlgo
Definition: pkcs7_common.h:267
error_t pkcs7FormatSignedData(const PrngAlgo *prngAlgo, void *prngContext, const Pkcs7SignedData *signedData, const void *signerPrivateKey, uint8_t *output, size_t *written)
Format signed-data content.
Definition: pkcs7_format.c:205
error_t pkcs7GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const uint8_t *digest, const Pkcs7SignerInfo *signerInfo, const void *privateKey, uint8_t *output, size_t *written)
Signature generation.
X509SignAlgoId digestEncryptionAlgo
Definition: pkcs7_common.h:269
#define OID_COMP(oid1, oidLen1, oid2)
Definition: oid.h:42
RSA private key.
Definition: rsa.h:68
X509OctetString content
Definition: pkcs7_common.h:319
Unauthenticated attributes.
Definition: pkcs7_common.h:252
uint8_t oidLen
Definition: lldp_tlv.h:299
Pkcs7SignerInfos signerInfos
Definition: pkcs7_common.h:357
@ PKCS7_VERSION_1
v1
Definition: pkcs7_common.h:166
Pkcs7SignerInfo signerInfos[PKCS7_MAX_SIGNER_INFOS]
Definition: pkcs7_common.h:283
const uint8_t SHA224_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:63
const uint8_t * value
Definition: x509_common.h:702
Common interface for hash algorithms.
Definition: crypto.h:1089
error_t rsassaPkcs1v15Sign(const RsaPrivateKey *key, const HashAlgo *hash, const uint8_t *digest, uint8_t *signature, size_t *signatureLen)
RSASSA-PKCS1-v1_5 signature generation operation.
Definition: rsa.c:935
PKCS #7 signature generation.
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
Authenticated attributes.
Definition: pkcs7_common.h:237
error_t pkcs7GenerateRsaSignature(const uint8_t *digest, const Pkcs7SignerInfo *signerInfo, const RsaPrivateKey *privateKey, uint8_t *output, size_t *written)
RSA signature generation.
PKCS #7 message formatting.
#define osMemset(p, value, length)
Definition: os_port.h:138
const uint8_t SHA1_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:61
X509OctetString raw
Definition: x509_common.h:724
Signature algorithm identifier.
Definition: x509_common.h:1088
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:215