]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c
75225e18e1fe9f689c43c5dbfae0dc98560da70d
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs1Oaep.c
1 /** @file
2 This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines.
3
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6 Copyright (C) 2016 Microsoft Corporation. All Rights Reserved.
7 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
8
9 **/
10
11 #include "InternalCryptLib.h"
12 #include <openssl/objects.h>
13 #include <openssl/rsa.h>
14 #include <openssl/x509.h>
15 #include <Library/MemoryAllocationLib.h>
16
17 /**
18 Encrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the
19 encrypted message in a newly allocated buffer.
20
21 Things that can cause a failure include:
22 - X509 key size does not match any known key size.
23 - Fail to parse X509 certificate.
24 - Fail to allocate an intermediate buffer.
25 - Null pointer provided for a non-optional parameter.
26 - Data size is too large for the provided key size (max size is a function of key size
27 and hash digest size).
28
29 @param[in] PublicKey A pointer to the DER-encoded X509 certificate that
30 will be used to encrypt the data.
31 @param[in] PublicKeySize Size of the X509 cert buffer.
32 @param[in] InData Data to be encrypted.
33 @param[in] InDataSize Size of the data buffer.
34 @param[in] PrngSeed [Optional] If provided, a pointer to a random seed buffer
35 to be used when initializing the PRNG. NULL otherwise.
36 @param[in] PrngSeedSize [Optional] If provided, size of the random seed buffer.
37 0 otherwise.
38 @param[out] EncryptedData Pointer to an allocated buffer containing the encrypted
39 message.
40 @param[out] EncryptedDataSize Size of the encrypted message buffer.
41
42 @retval TRUE Encryption was successful.
43 @retval FALSE Encryption failed.
44
45 **/
46 BOOLEAN
47 EFIAPI
48 Pkcs1v2Encrypt (
49 IN CONST UINT8 *PublicKey,
50 IN UINTN PublicKeySize,
51 IN UINT8 *InData,
52 IN UINTN InDataSize,
53 IN CONST UINT8 *PrngSeed, OPTIONAL
54 IN UINTN PrngSeedSize, OPTIONAL
55 OUT UINT8 **EncryptedData,
56 OUT UINTN *EncryptedDataSize
57 )
58 {
59 BOOLEAN Result;
60 CONST UINT8 *TempPointer;
61 X509 *CertData;
62 EVP_PKEY *InternalPublicKey;
63 EVP_PKEY_CTX *PkeyCtx;
64 UINT8 *OutData;
65 UINTN OutDataSize;
66
67 //
68 // Check input parameters.
69 //
70 if (PublicKey == NULL || InData == NULL ||
71 EncryptedData == NULL || EncryptedDataSize == NULL) {
72 return FALSE;
73 }
74
75 //
76 // Check public key size.
77 //
78 if (PublicKeySize > 0xFFFFFFFF) {
79 //
80 // Public key size is too large for implementation.
81 //
82 return FALSE;
83 }
84
85 *EncryptedData = NULL;
86 *EncryptedDataSize = 0;
87 Result = FALSE;
88 TempPointer = NULL;
89 CertData = NULL;
90 InternalPublicKey = NULL;
91 PkeyCtx = NULL;
92 OutData = NULL;
93 OutDataSize = 0;
94
95 //
96 // If it provides a seed then use it.
97 // Ohterwise, we'll seed with fixed values and hope that the PRNG has already been
98 // used enough to generate sufficient entropy.
99 //
100 if (PrngSeed != NULL) {
101 RandomSeed (PrngSeed, PrngSeedSize);
102 } else {
103 RandomSeed (NULL, 0);
104 }
105
106 //
107 // Parse the X509 cert and extract the public key.
108 //
109 TempPointer = PublicKey;
110 CertData = d2i_X509 (&CertData, &TempPointer, (UINT32)PublicKeySize);
111 if (CertData == NULL) {
112 //
113 // Fail to parse X509 cert.
114 //
115 goto _Exit;
116 }
117
118 //
119 // Extract the public key from the x509 cert in a format that
120 // OpenSSL can use.
121 //
122 InternalPublicKey = X509_get_pubkey (CertData);
123 if (InternalPublicKey == NULL) {
124 //
125 // Fail to extract public key.
126 //
127 goto _Exit;
128 }
129
130 //
131 // Create a context for the public key operation.
132 //
133 PkeyCtx = EVP_PKEY_CTX_new (InternalPublicKey, NULL);
134 if (PkeyCtx == NULL) {
135 //
136 // Fail to create contex.
137 //
138 goto _Exit;
139 }
140 //
141 // Initialize the context and set the desired padding.
142 //
143 if (EVP_PKEY_encrypt_init (PkeyCtx) <= 0 ||
144 EVP_PKEY_CTX_set_rsa_padding (PkeyCtx, RSA_PKCS1_OAEP_PADDING) <= 0) {
145 //
146 // Fail to initialize the context.
147 //
148 goto _Exit;
149 }
150
151 //
152 // Determine the required buffer length for malloc'ing.
153 //
154 if (EVP_PKEY_encrypt (PkeyCtx, NULL, &OutDataSize, InData, InDataSize) <= 0) {
155 //
156 // Fail to determine output buffer size.
157 //
158 goto _Exit;
159 }
160
161 //
162 // Allocate a buffer for the output data.
163 //
164 OutData = AllocatePool (OutDataSize);
165 if (OutData == NULL) {
166 //
167 // Fail to allocate the output buffer.
168 //
169 goto _Exit;
170 }
171
172 //
173 // Encrypt Data.
174 //
175 if (EVP_PKEY_encrypt (PkeyCtx, OutData, &OutDataSize, InData, InDataSize) <= 0) {
176 //
177 // Fail to encrypt data, need to free the output buffer.
178 //
179 FreePool (OutData);
180 OutData = NULL;
181 OutDataSize = 0;
182 goto _Exit;
183 }
184
185 //
186 // Encrypt done.
187 //
188 *EncryptedData = OutData;
189 *EncryptedDataSize = OutDataSize;
190 Result = TRUE;
191
192 _Exit:
193 //
194 // Release Resources
195 //
196 if (CertData != NULL) {
197 X509_free (CertData );
198 }
199 if (InternalPublicKey != NULL) {
200 EVP_PKEY_free (InternalPublicKey);
201 }
202 if (PkeyCtx != NULL) {
203 EVP_PKEY_CTX_free (PkeyCtx);
204 }
205
206 return Result;
207 }
208