pkcs7_sign_verify.c
Go to the documentation of this file.
1 /**
2  * @file pkcs7_sign_verify.c
3  * @brief PKCS #7 signature verification
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_parse.h"
38 #include "hash/hash_algorithms.h"
39 #include "pkix/x509_key_parse.h"
40 #include "encoding/asn1.h"
41 #include "encoding/oid.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (PKCS7_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Verify signature over signed-data content
50  * @param[in] signedData Pointer to the signed-data content
51  * @param[in] signerInfo Pointer to the signer information
52  * @param[in] signerCertInfo Signer's certificate
53  * @return Error code
54  **/
55 
57  const Pkcs7SignerInfo *signerInfo, const X509CertInfo *signerCertInfo)
58 {
59  error_t error;
60  Asn1Tag tag;
61  uint8_t calcDigest[MAX_HASH_DIGEST_SIZE];
62  const HashAlgo *hashAlgo;
63  const X509OctetString *msgDigest;
64 
65  //Point to the PKCS #9 Message Digest attribute
66  msgDigest = &signerInfo->authenticatedAttributes.messageDigest;
67 
68  //Debug message
69  TRACE_DEBUG("Message digest:\r\n");
70  TRACE_DEBUG_ARRAY(" ", msgDigest->value, msgDigest->length);
71 
72  //Get the hash algorithm that matches the specified OID
73  hashAlgo = pkcs7GetHashAlgo(signerInfo->digestAlgo.oid.value,
74  signerInfo->digestAlgo.oid.length);
75 
76  //Valid hash algorithm?
77  if(hashAlgo != NULL)
78  {
79  //The initial input to the message-digesting process is the "value" of
80  //the content being signed (refer to RFC 2315, section 9.3)
81  error = asn1ReadOctetString(signedData->contentInfo.content.value,
82  signedData->contentInfo.content.length, &tag);
83 
84  //Check status code
85  if(!error)
86  {
87  //Only the contents octets of the DER encoding of that field are
88  //digested, not the identifier octets or the length octets
89  error = hashAlgo->compute(tag.value, tag.length, calcDigest);
90  }
91 
92  //Check status code
93  if(!error)
94  {
95  //Debug message
96  TRACE_DEBUG("Calculated digest:\r\n");
97  TRACE_DEBUG_ARRAY(" ", calcDigest, hashAlgo->digestSize);
98 
99  //Check the message digest of the content
100  if(msgDigest->length == hashAlgo->digestSize ||
101  osMemcmp(msgDigest->value, calcDigest, hashAlgo->digestSize) == 0)
102  {
103  //Digest the DER encoding of the authenticatedAttributes field
104  error = pkcs7DigestAuthenticatedAttributes(signerInfo,
105  signerInfo->authenticatedAttributes.raw.value,
106  signerInfo->authenticatedAttributes.raw.length, calcDigest);
107  }
108  else
109  {
110  //The message digest is not valid
111  error = ERROR_INVALID_SIGNATURE;
112  }
113  }
114 
115  //Check status code
116  if(!error)
117  {
118  //The input to the signature verification process includes the result
119  //of the message digest calculation process and the signer's public key
120  error = pkcs7VerifySignature(calcDigest, signerInfo,
121  &signerCertInfo->tbsCert.subjectPublicKeyInfo,
122  &signerInfo->encryptedDigest);
123  }
124  }
125  else
126  {
127  //The specified hash algorithm is not supported
129  }
130 
131  //Return status code
132  return error;
133 }
134 
135 
136 /**
137  * @brief Signature verification
138  * @param[in] digest Message digest
139  * @param[in] signerInfo Pointer to the signer information
140  * @param[in] publicKeyInfo Signer's public key
141  * @param[in] signature Signature to be verified
142  * @return Error code
143  **/
144 
145 error_t pkcs7VerifySignature(const uint8_t *digest,
146  const Pkcs7SignerInfo *signerInfo, const X509SubjectPublicKeyInfo *publicKeyInfo,
147  const X509OctetString *signature)
148 {
149  error_t error;
150  size_t oidLen;
151  const uint8_t *oid;
152 
153  //Get the signature algorithm identifier
154  oid = signerInfo->digestEncryptionAlgo.oid.value;
155  oidLen = signerInfo->digestEncryptionAlgo.oid.length;
156 
157 #if (PKCS7_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
158  //RSA signature algorithm?
159  if(OID_COMP(oid, oidLen, RSA_ENCRYPTION_OID) == 0 ||
166  {
167  //Verify RSA signature (RSASSA-PKCS1-v1_5 signature scheme)
168  error = pkcs7VerifyRsaSignature(digest, signerInfo, publicKeyInfo,
169  signature);
170  }
171  else
172 #endif
173  //Unknown signature algorithm?
174  {
175  //Report an error
177  }
178 
179  //Return status code
180  return error;
181 }
182 
183 
184 /**
185  * @brief RSA signature verification
186  * @param[in] digest Message digest
187  * @param[in] signerInfo Pointer to the signer information
188  * @param[in] publicKeyInfo Signer's public key
189  * @param[in] signature Signature to be verified
190  * @return Error code
191  **/
192 
193 error_t pkcs7VerifyRsaSignature(const uint8_t *digest,
194  const Pkcs7SignerInfo *signerInfo, const X509SubjectPublicKeyInfo *publicKeyInfo,
195  const X509OctetString *signature)
196 {
197 #if (PKCS7_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
198  error_t error;
199  const HashAlgo *hashAlgo;
200  RsaPublicKey rsaPublicKey;
201 
202  //Initialize RSA public key
203  rsaInitPublicKey(&rsaPublicKey);
204 
205  //The rsaEncryption algorithm identifier is used to identify RSA (PKCS #1
206  //v1.5) signature values regardless of the message digest algorithm
207  //employed (refer to RFC 3370, section 3.2)
208  if(OID_COMP(signerInfo->digestEncryptionAlgo.oid.value,
210  {
211  //CMS implementations that include the RSA (PKCS #1 v1.5) signature
212  //algorithm must support the rsaEncryption signature value algorithm
213  //identifier
214  hashAlgo = pkcs7GetHashAlgo(signerInfo->digestAlgo.oid.value,
215  signerInfo->digestAlgo.oid.length);
216  }
217  else
218  {
219  //CMS implementations may support RSA (PKCS #1 v1.5) signature value
220  //algorithm identifiers that specify both the RSA (PKCS #1 v1.5)
221  //signature algorithm and the message digest algorithm
222  hashAlgo = pkcs7GetSignHashAlgo(signerInfo->digestEncryptionAlgo.oid.value,
223  signerInfo->digestEncryptionAlgo.oid.length);
224  }
225 
226  //Valid hash algorithm?
227  if(hashAlgo != NULL)
228  {
229  //Import the RSA public key
230  error = x509ImportRsaPublicKey(&rsaPublicKey, publicKeyInfo);
231 
232  //Check status code
233  if(!error)
234  {
235  //Verify RSA signature (RSASSA-PKCS1-v1_5 signature scheme)
236  error = rsassaPkcs1v15Verify(&rsaPublicKey, hashAlgo, digest,
237  signature->value, signature->length);
238  }
239  }
240  else
241  {
242  //Report an error
244  }
245 
246  //Release previously allocated resources
247  rsaFreePublicKey(&rsaPublicKey);
248 
249  //Return status code
250  return error;
251 #else
252  //Not implemented
253  return ERROR_NOT_IMPLEMENTED;
254 #endif
255 }
256 
257 
258 /**
259  * @brief Search a list of per-signer informations for a given signer
260  * @param[in] signerInfos Pointer to the collection of per-signer
261  * information
262  * @param[in] signerCertInfo Signer's certificate
263  * @param[out] signerInfo Pointer to the matching SignerInfo structure,
264  * if any
265  * @return Error code
266  **/
267 
269  const X509CertInfo *signerCertInfo, Pkcs7SignerInfo *signerInfo)
270 {
271  error_t error;
272  size_t n;
273  size_t length;
274  const uint8_t *data;
275 
276  //Point to the first signerInfo entry
277  data = signerInfos->raw.value;
278  length = signerInfos->raw.length;
279 
280  //signerInfos is a collection of per-signer information. There may be any
281  //number of elements in the collection, including zero (refer to RFC 2315,
282  //section 9.1)
283  while(length > 0)
284  {
285  //Per-signer information is represented in the type SignerInfo
286  error = pkcs7ParseSignerInfo(data, length, &n, signerInfo);
287  //Failed to decode ASN.1 tag?
288  if(error)
289  return error;
290 
291  //Matching issuer name?
293  signerInfo->issuerAndSerialNumber.name.raw.length,
294  signerCertInfo->tbsCert.issuer.raw.value,
295  signerCertInfo->tbsCert.issuer.raw.length))
296  {
297  //Compare the length of the serial numbers
298  if(signerInfo->issuerAndSerialNumber.serialNumber.length ==
299  signerCertInfo->tbsCert.serialNumber.length)
300  {
301  //Matching serial number?
303  signerCertInfo->tbsCert.serialNumber.value,
304  signerCertInfo->tbsCert.serialNumber.length) == 0)
305  {
306  //A matching signer has been found
307  return NO_ERROR;
308  }
309  }
310  }
311 
312  //Next field
313  data += n;
314  length -= n;
315  }
316 
317  //The specified signer was not found
318  return ERROR_NOT_FOUND;
319 }
320 
321 #endif
@ ERROR_NOT_FOUND
Definition: error.h:148
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
const uint8_t * value
Definition: x509_common.h:713
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
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
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
OID (Object Identifier)
Pkcs7AuthenticatedAttributes authenticatedAttributes
Definition: pkcs7_common.h:268
uint8_t data[]
Definition: ethernet.h:224
X509OctetString messageDigest
Definition: pkcs7_common.h:240
size_t digestSize
Definition: crypto.h:1095
Pkcs7ContentInfo contentInfo
Definition: pkcs7_common.h:354
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
error_t pkcs7VerifyRsaSignature(const uint8_t *digest, const Pkcs7SignerInfo *signerInfo, const X509SubjectPublicKeyInfo *publicKeyInfo, const X509OctetString *signature)
RSA signature verification.
uint8_t oid[]
Definition: lldp_tlv.h:300
const uint8_t SHA384_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:67
size_t length
Definition: asn1.h:109
#define MAX_HASH_DIGEST_SIZE
error_t asn1ReadOctetString(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an octet string from the input stream.
Definition: asn1.c:190
@ ERROR_UNSUPPORTED_HASH_ALGO
Definition: error.h:130
PKCS #7 message parsing.
X.509 certificate.
Definition: x509_common.h:1119
error_t pkcs7ParseSignerInfo(const uint8_t *data, size_t length, size_t *totalLength, Pkcs7SignerInfo *signerInfo)
Parse SignerInfo structure.
Definition: pkcs7_parse.c:577
error_t
Error codes.
Definition: error.h:43
error_t pkcs7DigestAuthenticatedAttributes(const Pkcs7SignerInfo *signerInfo, const uint8_t *data, size_t length, uint8_t *digest)
Digest the DER encoding of the authenticatedAttributes field.
Definition: pkcs7_common.c:382
error_t pkcs7FindSigner(const Pkcs7SignerInfos *signerInfos, const X509CertInfo *signerCertInfo, Pkcs7SignerInfo *signerInfo)
Search a list of per-signer informations for a given signer.
Signer information.
Definition: pkcs7_common.h:264
HashAlgoCompute compute
Definition: crypto.h:1098
ASN.1 tag.
Definition: asn1.h:105
RSA public key.
Definition: rsa.h:57
X509OctetString encryptedDigest
Definition: pkcs7_common.h:270
X509OctetString oid
Definition: x509_common.h:775
General definitions for cryptographic algorithms.
X509SerialNumber serialNumber
Definition: x509_common.h:1104
error_t pkcs7VerifySignedData(const Pkcs7SignedData *signedData, const Pkcs7SignerInfo *signerInfo, const X509CertInfo *signerCertInfo)
Verify signature over signed-data content.
uint8_t length
Definition: tcp.h:375
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
Collection of hash algorithms.
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
Signed data content.
Definition: pkcs7_common.h:351
Collection of signer informations.
Definition: pkcs7_common.h:280
PKCS #7 signature verification.
#define TRACE_DEBUG(...)
Definition: debug.h:119
error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash, const uint8_t *digest, const uint8_t *signature, size_t signatureLen)
RSASSA-PKCS1-v1_5 signature verification operation.
Definition: rsa.c:1068
X509AlgoId digestAlgo
Definition: pkcs7_common.h:267
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
X509SignAlgoId digestEncryptionAlgo
Definition: pkcs7_common.h:269
#define OID_COMP(oid1, oidLen1, oid2)
Definition: oid.h:42
error_t x509ImportRsaPublicKey(RsaPublicKey *publicKey, const X509SubjectPublicKeyInfo *publicKeyInfo)
Import an RSA public key.
uint8_t n
Subject Public Key Information extension.
Definition: x509_common.h:838
X509OctetString content
Definition: pkcs7_common.h:319
uint8_t oidLen
Definition: lldp_tlv.h:299
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 pkcs7VerifySignature(const uint8_t *digest, const Pkcs7SignerInfo *signerInfo, const X509SubjectPublicKeyInfo *publicKeyInfo, const X509OctetString *signature)
Signature verification.
Parsing of ASN.1 encoded keys.
bool_t x509CompareName(const uint8_t *name1, size_t nameLen1, const uint8_t *name2, size_t nameLen2)
Compare distinguished names.
Definition: x509_common.c:184
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
Octet string.
Definition: x509_common.h:701
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1109
X509OctetString raw
Definition: pkcs7_common.h:281
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
const uint8_t SHA1_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:61
X509OctetString raw
Definition: x509_common.h:724
const uint8_t * value
Definition: asn1.h:110
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:100
ASN.1 (Abstract Syntax Notation One)