]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c
CryptoPkg: Apply uncrustify changes
[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 {
73 return FALSE;
74 }
75
76 //
77 // Check public key size.
78 //
79 if (PublicKeySize > 0xFFFFFFFF) {
80 //
81 // Public key size is too large for implementation.
82 //
83 return FALSE;
84 }
85
86 *EncryptedData = NULL;
87 *EncryptedDataSize = 0;
88 Result = FALSE;
89 TempPointer = NULL;
90 CertData = NULL;
91 InternalPublicKey = NULL;
92 PkeyCtx = NULL;
93 OutData = NULL;
94 OutDataSize = 0;
95
96 //
97 // If it provides a seed then use it.
98 // Ohterwise, we'll seed with fixed values and hope that the PRNG has already been
99 // used enough to generate sufficient entropy.
100 //
101 if (PrngSeed != NULL) {
102 RandomSeed (PrngSeed, PrngSeedSize);
103 } else {
104 RandomSeed (NULL, 0);
105 }
106
107 //
108 // Parse the X509 cert and extract the public key.
109 //
110 TempPointer = PublicKey;
111 CertData = d2i_X509 (&CertData, &TempPointer, (UINT32)PublicKeySize);
112 if (CertData == NULL) {
113 //
114 // Fail to parse X509 cert.
115 //
116 goto _Exit;
117 }
118
119 //
120 // Extract the public key from the x509 cert in a format that
121 // OpenSSL can use.
122 //
123 InternalPublicKey = X509_get_pubkey (CertData);
124 if (InternalPublicKey == NULL) {
125 //
126 // Fail to extract public key.
127 //
128 goto _Exit;
129 }
130
131 //
132 // Create a context for the public key operation.
133 //
134 PkeyCtx = EVP_PKEY_CTX_new (InternalPublicKey, NULL);
135 if (PkeyCtx == NULL) {
136 //
137 // Fail to create contex.
138 //
139 goto _Exit;
140 }
141
142 //
143 // Initialize the context and set the desired padding.
144 //
145 if ((EVP_PKEY_encrypt_init (PkeyCtx) <= 0) ||
146 (EVP_PKEY_CTX_set_rsa_padding (PkeyCtx, RSA_PKCS1_OAEP_PADDING) <= 0))
147 {
148 //
149 // Fail to initialize the context.
150 //
151 goto _Exit;
152 }
153
154 //
155 // Determine the required buffer length for malloc'ing.
156 //
157 if (EVP_PKEY_encrypt (PkeyCtx, NULL, &OutDataSize, InData, InDataSize) <= 0) {
158 //
159 // Fail to determine output buffer size.
160 //
161 goto _Exit;
162 }
163
164 //
165 // Allocate a buffer for the output data.
166 //
167 OutData = AllocatePool (OutDataSize);
168 if (OutData == NULL) {
169 //
170 // Fail to allocate the output buffer.
171 //
172 goto _Exit;
173 }
174
175 //
176 // Encrypt Data.
177 //
178 if (EVP_PKEY_encrypt (PkeyCtx, OutData, &OutDataSize, InData, InDataSize) <= 0) {
179 //
180 // Fail to encrypt data, need to free the output buffer.
181 //
182 FreePool (OutData);
183 OutData = NULL;
184 OutDataSize = 0;
185 goto _Exit;
186 }
187
188 //
189 // Encrypt done.
190 //
191 *EncryptedData = OutData;
192 *EncryptedDataSize = OutDataSize;
193 Result = TRUE;
194
195 _Exit:
196 //
197 // Release Resources
198 //
199 if (CertData != NULL) {
200 X509_free (CertData);
201 }
202
203 if (InternalPublicKey != NULL) {
204 EVP_PKEY_free (InternalPublicKey);
205 }
206
207 if (PkeyCtx != NULL) {
208 EVP_PKEY_CTX_free (PkeyCtx);
209 }
210
211 return Result;
212 }