+/**\r
+ Verification callback function to override any existing callbacks in OpenSSL\r
+ for intermediate certificate supports.\r
+\r
+ @param[in] Status Original status before calling this callback.\r
+ @param[in] Context X509 store context.\r
+\r
+ @retval 1 Current X509 certificate is verified successfully.\r
+ @retval 0 Verification failed.\r
+\r
+**/\r
+STATIC int X509VerifyCb (int Status, X509_STORE_CTX *Context)\r
+{\r
+ X509_OBJECT *Obj;\r
+ int Error;\r
+ int Index;\r
+ int Count;\r
+\r
+ Obj = NULL;\r
+ Error = X509_STORE_CTX_get_error (Context);\r
+\r
+ //\r
+ // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT and X509_V_ERR_UNABLE_TO_GET_ISSUER_\r
+ // CERT_LOCALLY mean a X509 certificate is not self signed and its issuer\r
+ // can not be found in X509_verify_cert of X509_vfy.c.\r
+ // In order to support intermediate certificate node, we override the\r
+ // errors if the certification is obtained from X509 store, i.e. it is\r
+ // a trusted ceritifcate node that is enrolled by user.\r
+ // Besides,X509_V_ERR_CERT_UNTRUSTED and X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE\r
+ // are also ignored to enable such feature.\r
+ //\r
+ if ((Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) ||\r
+ (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {\r
+ Obj = (X509_OBJECT *) OPENSSL_malloc (sizeof (X509_OBJECT));\r
+ if (Obj == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Obj->type = X509_LU_X509;\r
+ Obj->data.x509 = Context->current_cert;\r
+\r
+ CRYPTO_w_lock (CRYPTO_LOCK_X509_STORE);\r
+\r
+ if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
+ Status = 1;\r
+ } else {\r
+ //\r
+ // If any certificate in the chain is enrolled as trusted certificate,\r
+ // pass the certificate verification.\r
+ //\r
+ if (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {\r
+ Count = sk_X509_num (Context->chain);\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Obj->data.x509 = sk_X509_value (Context->chain, Index);\r
+ if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
+ Status = 1;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ CRYPTO_w_unlock (CRYPTO_LOCK_X509_STORE);\r
+ }\r
+\r
+ if ((Error == X509_V_ERR_CERT_UNTRUSTED) ||\r
+ (Error == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) {\r
+ Status = 1;\r
+ }\r
+\r
+ if (Obj != NULL) {\r
+ OPENSSL_free (Obj);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message\r
+ Syntax Standard, version 1.5". This interface is only intended to be used for\r
+ application to perform PKCS#7 functionality validation.\r
+\r
+ @param[in] PrivateKey Pointer to the PEM-formatted private key data for\r
+ data signing.\r
+ @param[in] PrivateKeySize Size of the PEM private key data in bytes.\r
+ @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM\r
+ key data.\r
+ @param[in] InData Pointer to the content to be signed.\r
+ @param[in] InDataSize Size of InData in bytes.\r
+ @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.\r
+ @param[in] OtherCerts Pointer to an optional additional set of certificates to\r
+ include in the PKCS#7 signedData (e.g. any intermediate\r
+ CAs in the chain).\r
+ @param[out] SignedData Pointer to output PKCS#7 signedData.\r
+ @param[out] SignedDataSize Size of SignedData in bytes.\r
+\r
+ @retval TRUE PKCS#7 data signing succeeded.\r
+ @retval FALSE PKCS#7 data signing failed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Pkcs7Sign (\r
+ IN CONST UINT8 *PrivateKey,\r
+ IN UINTN PrivateKeySize,\r
+ IN CONST UINT8 *KeyPassword,\r
+ IN UINT8 *InData,\r
+ IN UINTN InDataSize,\r
+ IN UINT8 *SignCert,\r
+ IN UINT8 *OtherCerts OPTIONAL,\r
+ OUT UINT8 **SignedData,\r
+ OUT UINTN *SignedDataSize\r
+ )\r
+{\r
+ BOOLEAN Status;\r
+ EVP_PKEY *Key;\r
+ BIO *DataBio;\r
+ PKCS7 *Pkcs7;\r
+ UINT8 *RsaContext;\r
+ UINT8 *P7Data;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if ((PrivateKey == NULL) || (KeyPassword == NULL) || (InData == NULL)) {\r
+ return FALSE;\r
+ }\r
+ \r
+ if ((SignCert == NULL) || (SignedData == NULL) || (SignedDataSize == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ RsaContext = NULL;\r
+ Key = NULL;\r
+ Pkcs7 = NULL;\r
+ DataBio = NULL;\r
+ Status = FALSE;\r
+\r
+ //\r
+ // Retrieve RSA private key from PEM data.\r
+ //\r
+ Status = RsaGetPrivateKeyFromPem (\r
+ PrivateKey,\r
+ PrivateKeySize,\r
+ (CONST CHAR8 *) KeyPassword,\r
+ (VOID **) &RsaContext\r
+ );\r
+ if (!Status) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling\r
+ //\r
+ EVP_add_digest (EVP_md5());\r
+ EVP_add_digest (EVP_sha1());\r
+ EVP_add_digest (EVP_sha256());\r
+ RandomSeed (NULL, 0);\r
+\r
+ //\r
+ // Construct OpenSSL EVP_PKEY for private key.\r
+ //\r
+ Key = EVP_PKEY_new ();\r
+ if (Key == NULL) {\r
+ goto _Exit;\r
+ }\r
+ Key->save_type = EVP_PKEY_RSA;\r
+ Key->type = EVP_PKEY_type (EVP_PKEY_RSA);\r
+ Key->pkey.rsa = (RSA *) RsaContext;\r
+\r
+ //\r
+ // Convert the data to be signed to BIO format. \r
+ //\r
+ DataBio = BIO_new (BIO_s_mem ());\r
+ BIO_write (DataBio, InData, (int) InDataSize);\r
+\r
+ //\r
+ // Create the PKCS#7 signedData structure.\r
+ //\r
+ Pkcs7 = PKCS7_sign (\r
+ (X509 *) SignCert,\r
+ Key,\r
+ (STACK_OF(X509) *) OtherCerts,\r
+ DataBio,\r
+ PKCS7_BINARY\r
+ );\r
+ if (Pkcs7 == NULL) {\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Convert PKCS#7 signedData structure into DER-encoded buffer.\r
+ //\r
+ *SignedDataSize = i2d_PKCS7 (Pkcs7, NULL);\r
+ if (*SignedDataSize == 0) {\r
+ goto _Exit;\r
+ }\r
+ *SignedData = OPENSSL_malloc (*SignedDataSize);\r
+ P7Data = *SignedData;\r
+ *SignedDataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &P7Data);\r
+\r
+ Status = TRUE;\r
+\r
+_Exit:\r
+ //\r
+ // Release Resources\r
+ //\r
+ if (RsaContext != NULL) {\r
+ RsaFree (RsaContext);\r
+ if (Key != NULL) {\r
+ Key->pkey.rsa = NULL;\r
+ }\r
+ }\r
+\r
+ if (Key != NULL) {\r
+ EVP_PKEY_free (Key);\r
+ }\r
+\r
+ if (DataBio != NULL) {\r
+ BIO_free (DataBio);\r
+ }\r
+\r
+ if (Pkcs7 != NULL) {\r
+ PKCS7_free (Pkcs7);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r