ca0dd4f286480b3c15818d4a02abb4b0164c3294
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7.c
1 /** @file\r
2   PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
3 \r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "InternalCryptLib.h"\r
16 \r
17 #include <openssl/objects.h>\r
18 #include <openssl/x509.h>\r
19 #include <openssl/pkcs7.h>\r
20 \r
21 \r
22 /**\r
23   Verifies the validility of a PKCS#7 signed data as described in "PKCS #7: Cryptographic\r
24   Message Syntax Standard".\r
25 \r
26   If P7Data is NULL, then ASSERT().\r
27 \r
28   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.\r
29   @param[in]  P7Length     Length of the PKCS#7 message in bytes.\r
30   @param[in]  TrustedCert  Pointer to a trusted/root certificate encoded in DER, which\r
31                            is used for certificate chain verification.\r
32   @param[in]  CertLength   Length of the trusted certificate in bytes.\r
33   @param[in]  InData       Pointer to the content to be verified.\r
34   @param[in]  DataLength   Length of InData in bytes.\r
35 \r
36   @retval  TRUE  The specified PKCS#7 signed data is valid.\r
37   @retval  FALSE Invalid PKCS#7 signed data.\r
38 \r
39 **/\r
40 BOOLEAN\r
41 EFIAPI\r
42 Pkcs7Verify (\r
43   IN  CONST UINT8  *P7Data,\r
44   IN  UINTN        P7Length,\r
45   IN  CONST UINT8  *TrustedCert,\r
46   IN  UINTN        CertLength,\r
47   IN  CONST UINT8  *InData,\r
48   IN  UINTN        DataLength\r
49   )\r
50 {\r
51   PKCS7       *Pkcs7;\r
52   UINT8       *Content;\r
53   BIO         *CertBio;\r
54   BIO         *DataBio;\r
55   BOOLEAN     Status;\r
56   X509        *Cert;\r
57   X509_STORE  *CertStore;\r
58 \r
59   //\r
60   // ASSERT if P7Data is NULL\r
61   //\r
62   ASSERT (P7Data != NULL);\r
63 \r
64   Status    = FALSE;\r
65   Pkcs7     = NULL;\r
66   CertBio   = NULL;\r
67   DataBio   = NULL;\r
68   Cert      = NULL;\r
69   CertStore = NULL;\r
70 \r
71   //\r
72   // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
73   //\r
74   EVP_add_digest (EVP_md5());\r
75   EVP_add_digest (EVP_sha1());\r
76   EVP_add_digest (EVP_sha256());\r
77 \r
78   //\r
79   // Retrieve PKCS#7 Data (DER encoding)\r
80   //\r
81   Pkcs7 = d2i_PKCS7 (NULL, &P7Data, (int)P7Length);\r
82   if (Pkcs7 == NULL) {\r
83     goto _Exit;\r
84   }\r
85 \r
86   //\r
87   // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
88   //\r
89   if (!PKCS7_type_is_signed (Pkcs7)) {\r
90     goto _Exit;\r
91   }\r
92 \r
93   //\r
94   // Check PKCS#7 embedded signed content with InData.\r
95   //\r
96   if (InData != NULL) {\r
97     //\r
98     // NOTE: PKCS7_dataDecode() didn't work for Authenticode-format signed data due to\r
99     //       some authenticode-specific structure. Use opaque ASN.1 string to retrieve\r
100     //       PKCS#7 ContentInfo here.\r
101     //\r
102     Content = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data);\r
103 \r
104     // Ignore two bytes for DER encoding of ASN.1 "SEQUENCE"\r
105     if (CompareMem (Content + 2, InData, DataLength) != 0) {\r
106       goto _Exit;\r
107     }\r
108   }\r
109 \r
110   //\r
111   // Read DER-encoded root certificate and Construct X509 Certificate\r
112   //\r
113   CertBio = BIO_new (BIO_s_mem ());\r
114   BIO_write (CertBio, TrustedCert, (int)CertLength);\r
115   if (CertBio == NULL) {\r
116     goto _Exit;\r
117   }\r
118   Cert = d2i_X509_bio (CertBio, NULL);\r
119   if (Cert == NULL) {\r
120     goto _Exit;\r
121   }\r
122 \r
123   //\r
124   // Setup X509 Store for trusted certificate\r
125   //\r
126   CertStore = X509_STORE_new ();\r
127   if (CertStore == NULL) {\r
128     goto _Exit;\r
129   }\r
130   if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
131     goto _Exit;\r
132   }\r
133 \r
134   //\r
135   // For generic PKCS#7 handling, InData may be NULL if the content is present\r
136   // in PKCS#7 structure. So ignore NULL checking here.\r
137   //\r
138   DataBio = BIO_new (BIO_s_mem ());\r
139   BIO_write (DataBio, InData, (int)DataLength);\r
140 \r
141   //\r
142   // Verifies the PKCS#7 signedData structure\r
143   //\r
144   Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, 0);\r
145 \r
146 _Exit:\r
147   //\r
148   // Release Resources\r
149   //\r
150   BIO_free (DataBio);\r
151   BIO_free (CertBio);\r
152   X509_free (Cert);\r
153   X509_STORE_free (CertStore);\r
154   PKCS7_free (Pkcs7);\r
155 \r
156   return Status;\r
157 }\r