pkcs7_common.c
Go to the documentation of this file.
1 /**
2  * @file pkcs7_common.c
3  * @brief PKCS #7 common definitions
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_common.h"
37 #include "hash/hash_algorithms.h"
39 #include "pkc/rsa.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 //PKCS #7 OID (1.2.840.113549.1.7)
48 const uint8_t PKCS7_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07};
49 //PKCS #7 Data OID (1.2.840.113549.1.7.1)
50 const uint8_t PKCS7_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01};
51 //PKCS #7 Signed Data OID (1.2.840.113549.1.7.2)
52 const uint8_t PKCS7_SIGNED_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02};
53 //PKCS #7 Enveloped Data OID (1.2.840.113549.1.7.3)
54 const uint8_t PKCS7_ENVELOPED_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03};
55 //PKCS #7 Signed And Enveloped Data OID (1.2.840.113549.1.7.4)
56 const uint8_t PKCS7_SIGNED_AND_ENVELOPED_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04};
57 //PKCS #7 Digested Data OID (1.2.840.113549.1.7.5)
58 const uint8_t PKCS7_DIGESTED_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05};
59 //PKCS #7 Encrypted Data OID (1.2.840.113549.1.7.6)
60 const uint8_t PKCS7_ENCRYPTED_DATA_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06};
61 
62 //PKCS #9 Content Type OID (1.2.840.113549.1.9.3)
63 const uint8_t PKCS9_CONTENT_TYPE_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03};
64 //PKCS #9 Message Digest OID (1.2.840.113549.1.9.4)
65 const uint8_t PKCS9_MESSAGE_DIGEST_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04};
66 //PKCS #9 Signing Time OID (1.2.840.113549.1.9.5)
67 const uint8_t PKCS9_SIGNING_TIME_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05};
68 
69 
70 /**
71  * @brief Get the hash algorithm that matches the specified OID
72  * @param[in] oid Algorithm identifier
73  * @param[in] length Length of the algorithm identifier, in bytes
74  * @return Hash algorithm
75  **/
76 
77 const HashAlgo *pkcs7GetHashAlgo(const uint8_t *oid, size_t length)
78 {
79  const HashAlgo *hashAlgo;
80 
81 #if (PKCS7_MD5_SUPPORT == ENABLED && MD5_SUPPORT == ENABLED)
82  //MD5 algorithm identifier?
83  if(OID_COMP(oid, length, MD5_OID) == 0)
84  {
85  hashAlgo = MD5_HASH_ALGO;
86  }
87  else
88 #endif
89 #if (PKCS7_SHA1_SUPPORT == ENABLED && SHA1_SUPPORT == ENABLED)
90  //SHA-1 algorithm identifier?
91  if(OID_COMP(oid, length, SHA1_OID) == 0)
92  {
93  hashAlgo = SHA1_HASH_ALGO;
94  }
95  else
96 #endif
97 #if (PKCS7_SHA224_SUPPORT == ENABLED && SHA224_SUPPORT == ENABLED)
98  //SHA-224 algorithm identifier?
99  if(OID_COMP(oid, length, SHA224_OID) == 0)
100  {
101  hashAlgo = SHA224_HASH_ALGO;
102  }
103  else
104 #endif
105 #if (PKCS7_SHA256_SUPPORT == ENABLED && SHA256_SUPPORT == ENABLED)
106  //SHA-256 algorithm identifier?
107  if(OID_COMP(oid, length, SHA256_OID) == 0)
108  {
109  hashAlgo = SHA256_HASH_ALGO;
110  }
111  else
112 #endif
113 #if (PKCS7_SHA384_SUPPORT == ENABLED && SHA384_SUPPORT == ENABLED)
114  //SHA-384 algorithm identifier?
115  if(OID_COMP(oid, length, SHA384_OID) == 0)
116  {
117  hashAlgo = SHA384_HASH_ALGO;
118  }
119  else
120 #endif
121 #if (PKCS7_SHA512_SUPPORT == ENABLED && SHA512_SUPPORT == ENABLED)
122  //SHA-512 algorithm identifier?
123  if(OID_COMP(oid, length, SHA512_OID) == 0)
124  {
125  hashAlgo = SHA512_HASH_ALGO;
126  }
127  else
128 #endif
129  //Unknown algorithm identifier?
130  {
131  hashAlgo = NULL;
132  }
133 
134  //Return the hash algorithm that matches the specified OID
135  return hashAlgo;
136 }
137 
138 
139 /**
140  * @brief Get the signature hash algorithm that matches the specified OID
141  * @param[in] oid Algorithm identifier
142  * @param[in] length Length of the algorithm identifier, in bytes
143  * @return Hash algorithm
144  **/
145 
146 const HashAlgo *pkcs7GetSignHashAlgo(const uint8_t *oid, size_t length)
147 {
148  const HashAlgo *hashAlgo;
149 
150 #if (PKCS7_MD5_SUPPORT == ENABLED && MD5_SUPPORT == ENABLED)
151  //MD5 algorithm identifier?
153  {
154  hashAlgo = MD5_HASH_ALGO;
155  }
156  else
157 #endif
158 #if (PKCS7_SHA1_SUPPORT == ENABLED && SHA1_SUPPORT == ENABLED)
159  //SHA-1 algorithm identifier?
161  {
162  hashAlgo = SHA1_HASH_ALGO;
163  }
164  else
165 #endif
166 #if (PKCS7_SHA224_SUPPORT == ENABLED && SHA224_SUPPORT == ENABLED)
167  //SHA-224 algorithm identifier?
169  {
170  hashAlgo = SHA224_HASH_ALGO;
171  }
172  else
173 #endif
174 #if (PKCS7_SHA256_SUPPORT == ENABLED && SHA256_SUPPORT == ENABLED)
175  //SHA-256 algorithm identifier?
177  {
178  hashAlgo = SHA256_HASH_ALGO;
179  }
180  else
181 #endif
182 #if (PKCS7_SHA384_SUPPORT == ENABLED && SHA384_SUPPORT == ENABLED)
183  //SHA-384 algorithm identifier?
185  {
186  hashAlgo = SHA384_HASH_ALGO;
187  }
188  else
189 #endif
190 #if (PKCS7_SHA512_SUPPORT == ENABLED && SHA512_SUPPORT == ENABLED)
191  //SHA-512 algorithm identifier?
193  {
194  hashAlgo = SHA512_HASH_ALGO;
195  }
196  else
197 #endif
198  //Unknown algorithm identifier?
199  {
200  hashAlgo = NULL;
201  }
202 
203  //Return the hash algorithm that matches the specified OID
204  return hashAlgo;
205 }
206 
207 
208 /**
209  * @brief Get the cipher algorithm that matches the specified OID
210  * @param[in] oid Algorithm identifier
211  * @param[in] length Length of the algorithm identifier, in bytes
212  * @return Cipher algorithm
213  **/
214 
215 const CipherAlgo *pkcs7GetCipherAlgo(const uint8_t *oid, size_t length)
216 {
217  const CipherAlgo *cipherAlgo;
218 
219 #if (PKCS7_DES_SUPPORT == ENABLED && DES_SUPPORT == ENABLED)
220  //DES-CBC algorithm identifier?
221  if(OID_COMP(oid, length, DES_CBC_OID) == 0)
222  {
223  cipherAlgo = DES_CIPHER_ALGO;
224  }
225  else
226 #endif
227 #if (PKCS7_3DES_SUPPORT == ENABLED && DES3_SUPPORT == ENABLED)
228  //DES-EDE3-CBC algorithm identifier?
229  if(OID_COMP(oid, length, DES_EDE3_CBC_OID) == 0)
230  {
231  cipherAlgo = DES3_CIPHER_ALGO;
232  }
233  else
234 #endif
235 #if (PKCS7_AES_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
236  //AES128-CBC algorithm identifier?
237  if(OID_COMP(oid, length, AES128_CBC_OID) == 0)
238  {
239  cipherAlgo = AES_CIPHER_ALGO;
240  }
241  //AES192-CBC algorithm identifier?
242  else if(OID_COMP(oid, length, AES192_CBC_OID) == 0)
243  {
244  cipherAlgo = AES_CIPHER_ALGO;
245  }
246  //AES256-CBC algorithm identifier?
247  else if(OID_COMP(oid, length, AES256_CBC_OID) == 0)
248  {
249  cipherAlgo = AES_CIPHER_ALGO;
250  }
251  else
252 #endif
253  //Unknown algorithm identifier?
254  {
255  cipherAlgo = NULL;
256  }
257 
258  //Return the cipher algorithm that matches the specified OID
259  return cipherAlgo;
260 }
261 
262 
263 /**
264  * @brief Get the encryption key length to be used for PBES2 operation
265  * @param[in] oid Encryption algorithm identifier
266  * @param[in] length Length of the encryption algorithm identifier, in bytes
267  * @return Encryption key length
268  **/
269 
270 uint_t pkcs7GetKeyLength(const uint8_t *oid, size_t length)
271 {
272  uint_t keyLen;
273 
274 #if (PKCS7_DES_SUPPORT == ENABLED && DES_SUPPORT == ENABLED)
275  //DES-CBC algorithm identifier?
276  if(OID_COMP(oid, length, DES_CBC_OID) == 0)
277  {
278  keyLen = 8;
279  }
280  else
281 #endif
282 #if (PKCS7_3DES_SUPPORT == ENABLED && DES3_SUPPORT == ENABLED)
283  //DES-EDE3-CBC algorithm identifier?
284  if(OID_COMP(oid, length, DES_EDE3_CBC_OID) == 0)
285  {
286  keyLen = 24;
287  }
288  else
289 #endif
290 #if (PKCS7_AES_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
291  //AES128-CBC algorithm identifier?
292  if(OID_COMP(oid, length, AES128_CBC_OID) == 0)
293  {
294  keyLen = 16;
295  }
296  //AES192-CBC algorithm identifier?
297  else if(OID_COMP(oid, length, AES192_CBC_OID) == 0)
298  {
299  keyLen = 24;
300  }
301  //AES256-CBC algorithm identifier?
302  else if(OID_COMP(oid, length, AES256_CBC_OID) == 0)
303  {
304  keyLen = 32;
305  }
306  else
307 #endif
308  //Unknown algorithm identifier?
309  {
310  keyLen = 0;
311  }
312 
313  //Return the encryption key length that matches the specified OID
314  return keyLen;
315 }
316 
317 
318 /**
319  * @brief Compare attributes
320  * @param[in] attribute1 Pointer to the first attribute
321  * @param[in] attributeLen1 Length of the first attribute
322  * @param[in] attribute2 Pointer to the second attribute
323  * @param[in] attributeLen2 Length of the second attribute
324  * @retval 0 Attributes are equal
325  * @retval -1 The first attribute precedes the second attribute
326  * @retval 1 The second attribute precedes the first attribute
327  **/
328 
329 int_t pkcs7CompAttributes(const uint8_t *attribute1, size_t attributeLen1,
330  const uint8_t *attribute2, size_t attributeLen2)
331 {
332  size_t i;
333  size_t n;
334 
335  //The encodings are compared as octet strings with the shorter components
336  //being padded at their trailing end with 0-octets
337  n = MIN(attributeLen1, attributeLen2);
338 
339  //Compare octet strings
340  for(i = 0; i < n; i++)
341  {
342  if(attribute1[i] < attribute2[i])
343  {
344  return -1;
345  }
346  else if(attribute1[i] > attribute2[i])
347  {
348  return 1;
349  }
350  else
351  {
352  }
353  }
354 
355  //Check whether the first attribute is shorter than the second attribute
356  if(attributeLen1 < attributeLen2)
357  {
358  return -1;
359  }
360  else if(attributeLen1 > attributeLen2)
361  {
362  return 1;
363  }
364  else
365  {
366  }
367 
368  //The attributes are equal
369  return 0;
370 }
371 
372 
373 /**
374  * @brief Digest the DER encoding of the authenticatedAttributes field
375  * @param[in] signerInfo Pointer to the signer information
376  * @param[in] data Content octets of authenticatedAttributes field
377  * @param[in] length Length of the content octets
378  * @param[out] digest Resulting message digest
379  * @return Error code
380  **/
381 
383  const uint8_t *data, size_t length, uint8_t *digest)
384 {
385  error_t error;
386  size_t n;
387  uint8_t buffer[8];
388  const HashAlgo *hashAlgo;
389  HashContext hashContext;
390  Asn1Tag tag;
391 
392  //The rsaEncryption algorithm identifier is used to identify RSA (PKCS #1
393  //v1.5) signature values regardless of the message digest algorithm
394  //employed (refer to RFC 3370, section 3.2)
395  if(OID_COMP(signerInfo->digestEncryptionAlgo.oid.value,
397  {
398  //CMS implementations that include the RSA (PKCS #1 v1.5) signature
399  //algorithm must support the rsaEncryption signature value algorithm
400  //identifier
401  hashAlgo = pkcs7GetHashAlgo(signerInfo->digestAlgo.oid.value,
402  signerInfo->digestAlgo.oid.length);
403  }
404  else
405  {
406  //CMS implementations may support RSA (PKCS #1 v1.5) signature value
407  //algorithm identifiers that specify both the RSA (PKCS #1 v1.5)
408  //signature algorithm and the message digest algorithm
409  hashAlgo = pkcs7GetSignHashAlgo(signerInfo->digestEncryptionAlgo.oid.value,
410  signerInfo->digestEncryptionAlgo.oid.length);
411  }
412 
413  //Valid hash algorithm?
414  if(hashAlgo != NULL)
415  {
416  //The IMPLICIT [0] tag in the authenticatedAttributes field is not part
417  //of the Attributes value. The Attributes value's tag is SET OF (refer to
418  //RFC 2315, section 9.3)
419  tag.constructed = TRUE;
421  tag.objType = ASN1_TYPE_SET;
422  tag.length = length;
423 
424  //Write the corresponding ASN.1 tag
425  error = asn1WriteHeader(&tag, FALSE, buffer, &n);
426 
427  //Chech status code
428  if(!error)
429  {
430  //The DER encoding of the SET OF tag, rather than of the IMPLICIT [0]
431  //tag, is to be digested along with the length and contents octets of
432  //the Attributes value
433  hashAlgo->init(&hashContext);
434  hashAlgo->update(&hashContext, buffer, n);
435  hashAlgo->update(&hashContext, data, length);
436  hashAlgo->final(&hashContext, digest);
437 
438  //Debug message
439  TRACE_DEBUG("Message digest:\r\n");
440  TRACE_DEBUG_ARRAY(" ", digest, hashAlgo->digestSize);
441  }
442  }
443  else
444  {
445  //Report an error
447  }
448 
449  //Return status code
450  return error;
451 }
452 
453 #endif
HashAlgoInit init
Definition: crypto.h:1099
Generic hash algorithm context.
#define SHA256_HASH_ALGO
Definition: sha256.h:49
#define SHA1_HASH_ALGO
Definition: sha1.h:49
const uint8_t PKCS7_DIGESTED_DATA_OID[9]
Definition: pkcs7_common.c:58
const HashAlgo * pkcs7GetHashAlgo(const uint8_t *oid, size_t length)
Get the hash algorithm that matches the specified OID.
Definition: pkcs7_common.c:77
#define SHA512_HASH_ALGO
Definition: sha512.h:49
const uint8_t MD5_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:59
signed int int_t
Definition: compiler_port.h:56
const uint8_t SHA512_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:69
OID (Object Identifier)
#define TRUE
Definition: os_port.h:50
Collection of AEAD algorithms.
uint8_t data[]
Definition: ethernet.h:224
error_t asn1WriteHeader(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag header.
Definition: asn1.c:501
size_t digestSize
Definition: crypto.h:1095
HashAlgoUpdate update
Definition: crypto.h:1100
const uint8_t DES_CBC_OID[5]
Definition: des.c:270
const CipherAlgo * pkcs7GetCipherAlgo(const uint8_t *oid, size_t length)
Get the cipher algorithm that matches the specified OID.
Definition: pkcs7_common.c:215
uint8_t oid[]
Definition: lldp_tlv.h:300
const uint8_t PKCS9_CONTENT_TYPE_OID[9]
Definition: pkcs7_common.c:63
const uint8_t SHA384_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:67
const uint8_t PKCS7_ENCRYPTED_DATA_OID[9]
Definition: pkcs7_common.c:60
size_t length
Definition: asn1.h:109
#define FALSE
Definition: os_port.h:46
@ ERROR_UNSUPPORTED_HASH_ALGO
Definition: error.h:130
PKCS #7 common definitions.
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
Signer information.
Definition: pkcs7_common.h:264
int_t pkcs7CompAttributes(const uint8_t *attribute1, size_t attributeLen1, const uint8_t *attribute2, size_t attributeLen2)
Compare attributes.
Definition: pkcs7_common.c:329
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
ASN.1 tag.
Definition: asn1.h:105
const uint8_t PKCS7_OID[8]
Definition: pkcs7_common.c:48
const uint8_t SHA256_OID[9]
Definition: sha256.c:80
#define MD5_HASH_ALGO
Definition: md5.h:49
X509OctetString oid
Definition: x509_common.h:775
uint_t pkcs7GetKeyLength(const uint8_t *oid, size_t length)
Get the encryption key length to be used for PBES2 operation.
Definition: pkcs7_common.c:270
const uint8_t PKCS9_MESSAGE_DIGEST_OID[9]
Definition: pkcs7_common.c:65
General definitions for cryptographic algorithms.
const uint8_t DES_EDE3_CBC_OID[8]
Definition: des3.c:48
RSA public-key cryptography standard.
#define DES_CIPHER_ALGO
Definition: des.h:45
uint_t objClass
Definition: asn1.h:107
const uint8_t MD5_OID[8]
Definition: md5.c:80
uint8_t length
Definition: tcp.h:375
X509OctetString oid
Definition: x509_common.h:1089
#define MIN(a, b)
Definition: os_port.h:63
const uint8_t AES256_CBC_OID[9]
Definition: aes.c:208
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
HashAlgoFinal final
Definition: crypto.h:1101
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
#define SHA384_HASH_ALGO
Definition: sha384.h:45
const uint8_t AES128_CBC_OID[9]
Definition: aes.c:182
#define TRACE_DEBUG(...)
Definition: debug.h:119
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
uint8_t n
const uint8_t PKCS7_SIGNED_DATA_OID[9]
Definition: pkcs7_common.c:52
const uint8_t PKCS9_SIGNING_TIME_OID[9]
Definition: pkcs7_common.c:67
const uint8_t PKCS7_SIGNED_AND_ENVELOPED_DATA_OID[9]
Definition: pkcs7_common.c:56
Common interface for encryption algorithms.
Definition: crypto.h:1111
bool_t constructed
Definition: asn1.h:106
const uint8_t SHA512_OID[9]
Definition: sha512.c:97
#define AES_CIPHER_ALGO
Definition: aes.h:45
const uint8_t SHA1_OID[5]
Definition: sha1.c:73
#define SHA224_HASH_ALGO
Definition: sha224.h:45
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
const uint8_t SHA224_OID[9]
Definition: sha224.c:47
#define DES3_CIPHER_ALGO
Definition: des3.h:46
const uint8_t PKCS7_ENVELOPED_DATA_OID[9]
Definition: pkcs7_common.c:54
unsigned int uint_t
Definition: compiler_port.h:57
const uint8_t SHA384_OID[9]
Definition: sha384.c:47
@ ASN1_TYPE_SET
Definition: asn1.h:84
const uint8_t SHA1_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:61
const uint8_t AES192_CBC_OID[9]
Definition: aes.c:195
Debugging facilities.
uint_t objType
Definition: asn1.h:108
ASN.1 (Abstract Syntax Notation One)