VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/key-file.cpp@ 100528

Last change on this file since 100528 was 100528, checked in by vboxsync, 17 months ago

IPRT/PKCS8: Added the ability to load PKCS\#8 EncryptedPrivateKey format. bugref:10299

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/* $Id: key-file.cpp 100528 2023-07-11 22:52:34Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Cryptographic Keys, File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_CRYPTO
42#include "internal/iprt.h"
43#include <iprt/crypto/key.h>
44
45#include <iprt/alloca.h>
46#include <iprt/asm.h>
47#include <iprt/assert.h>
48#include <iprt/ctype.h>
49#include <iprt/err.h>
50#include <iprt/log.h>
51#include <iprt/mem.h>
52#include <iprt/memsafer.h>
53#include <iprt/path.h>
54#include <iprt/string.h>
55#include <iprt/crypto/rsa.h>
56#include <iprt/crypto/pkcs8.h>
57#include <iprt/crypto/pkix.h>
58#include <iprt/crypto/x509.h>
59
60#include "internal/magics.h"
61#include "key-internal.h"
62
63#ifdef IPRT_WITH_OPENSSL
64# include "internal/iprt-openssl.h"
65# include "internal/openssl-pre.h"
66# include <openssl/err.h>
67# include <openssl/evp.h>
68# include <openssl/pkcs12.h>
69# include "internal/openssl-post.h"
70# ifndef OPENSSL_VERSION_NUMBER
71# error "Missing OPENSSL_VERSION_NUMBER!"
72# endif
73#endif
74
75
76/*********************************************************************************************************************************
77* Header Files *
78*********************************************************************************************************************************/
79/** RSA public key marker words. */
80static RTCRPEMMARKERWORD const g_aWords_RsaPublicKey[] =
81{ { RT_STR_TUPLE("RSA") }, { RT_STR_TUPLE("PUBLIC") }, { RT_STR_TUPLE("KEY") } };
82/** Generic public key marker words. */
83static RTCRPEMMARKERWORD const g_aWords_PublicKey[] =
84{ { RT_STR_TUPLE("PUBLIC") }, { RT_STR_TUPLE("KEY") } };
85
86/** Public key markers. */
87RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPublicMarkers[] =
88{
89 { g_aWords_RsaPublicKey, RT_ELEMENTS(g_aWords_RsaPublicKey) },
90 { g_aWords_PublicKey, RT_ELEMENTS(g_aWords_PublicKey) },
91};
92/** Number of entries in g_aRTCrKeyPublicMarkers. */
93RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPublicMarkers = RT_ELEMENTS(g_aRTCrKeyPublicMarkers);
94
95
96/** RSA private key marker words. */
97static RTCRPEMMARKERWORD const g_aWords_RsaPrivateKey[] =
98{ { RT_STR_TUPLE("RSA") }, { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
99/** Generic encrypted private key marker words. */
100static RTCRPEMMARKERWORD const g_aWords_EncryptedPrivateKey[] =
101{ { RT_STR_TUPLE("ENCRYPTED") }, { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
102/** Generic private key marker words. */
103static RTCRPEMMARKERWORD const g_aWords_PrivateKey[] =
104{ { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
105
106/** Private key markers. */
107RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPrivateMarkers[] =
108{
109 { g_aWords_RsaPrivateKey, RT_ELEMENTS(g_aWords_RsaPrivateKey) },
110 { g_aWords_EncryptedPrivateKey, RT_ELEMENTS(g_aWords_EncryptedPrivateKey) },
111 { g_aWords_PrivateKey, RT_ELEMENTS(g_aWords_PrivateKey) },
112};
113/** Number of entries in g_aRTCrKeyPrivateMarkers. */
114RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPrivateMarkers = RT_ELEMENTS(g_aRTCrKeyPrivateMarkers);
115
116
117/** Private and public key markers. */
118RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyAllMarkers[] =
119{
120 { g_aWords_RsaPublicKey, RT_ELEMENTS(g_aWords_RsaPublicKey) },
121 { g_aWords_PublicKey, RT_ELEMENTS(g_aWords_PublicKey) },
122 { g_aWords_RsaPrivateKey, RT_ELEMENTS(g_aWords_RsaPrivateKey) },
123 { g_aWords_EncryptedPrivateKey, RT_ELEMENTS(g_aWords_EncryptedPrivateKey) },
124 { g_aWords_PrivateKey, RT_ELEMENTS(g_aWords_PrivateKey) },
125};
126/** Number of entries in g_aRTCrKeyAllMarkers. */
127RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyAllMarkers = RT_ELEMENTS(g_aRTCrKeyAllMarkers);
128
129
130/**
131 * Creates a key from a raw PKCS\#8 PrivateKeyInfo structure.
132 *
133 * This is common code to both kKeyFormat_PrivateKeyInfo and
134 * kKeyFormat_EncryptedPrivateKeyInfo.
135 *
136 * @returns IPRT status code.
137 * @param phKey Where to return the key handle on success.
138 * @param pPrimaryCursor Cursor structure to use.
139 * @param pbRaw The raw PrivateKeyInfo bytes.
140 * @param cbRaw Size of the raw PrivateKeyInfo structure.
141 * @param pErrInfo Where to return additional error information.
142 * @param pszErrorTag What to tag the decoding with.
143 */
144static int rtCrKeyCreateFromPrivateKeyInfo(PRTCRKEY phKey, PRTASN1CURSORPRIMARY pPrimaryCursor,
145 uint8_t const *pbRaw, size_t cbRaw, PRTERRINFO pErrInfo, const char *pszErrorTag)
146
147{
148 RTCRPKCS8PRIVATEKEYINFO PrivateKeyInfo;
149 RT_ZERO(PrivateKeyInfo);
150 RTAsn1CursorInitPrimary(pPrimaryCursor, pbRaw, (uint32_t)cbRaw, pErrInfo, &g_RTAsn1DefaultAllocator,
151 RTASN1CURSOR_FLAGS_DER, pszErrorTag);
152 int rc = RTCrPkcs8PrivateKeyInfo_DecodeAsn1(&pPrimaryCursor->Cursor, 0, &PrivateKeyInfo,
153 pszErrorTag ? pszErrorTag : "PrivateKeyInfo");
154 if (RT_SUCCESS(rc))
155 {
156 /*
157 * Load the private key according to it's algorithm.
158 * We currently only support RSA (pkcs1-RsaEncryption).
159 */
160 if (RTAsn1ObjId_CompareWithString(&PrivateKeyInfo.PrivateKeyAlgorithm.Algorithm, RTCRX509ALGORITHMIDENTIFIERID_RSA) == 0)
161 rc = rtCrKeyCreateRsaPrivate(phKey, PrivateKeyInfo.PrivateKey.Asn1Core.uData.pv,
162 PrivateKeyInfo.PrivateKey.Asn1Core.cb, pErrInfo, pszErrorTag);
163 else
164 rc = RTERRINFO_LOG_SET(pErrInfo, VERR_CR_KEY_FORMAT_NOT_SUPPORTED,
165 "Support for PKCS#8 PrivateKeyInfo for non-RSA keys is not yet implemented");
166 RTCrPkcs8PrivateKeyInfo_Delete(&PrivateKeyInfo);
167 }
168 return rc;
169}
170
171
172/**
173 * Decrypts a PEM message.
174 *
175 * @returns IPRT status code
176 * @param pEncryptedKey The encrypted private key information.
177 * @param pszPassword The password to use to decrypt the key text.
178 * @param ppbDecrypted Where to return the decrypted message. Free using RTMemSaferFree.
179 * @param pcbDecrypted Where to return the length of the decrypted message.
180 * @param pcbDecryptedAlloced Where to return the allocation size.
181 * @param pErrInfo Where to return additional error information.
182 */
183static int rtCrKeyDecryptPkcs8Info(PRTCRPKCS8ENCRYPTEDPRIVATEKEYINFO pEncryptedKey, const char *pszPassword,
184 uint8_t **ppbDecrypted, size_t *pcbDecrypted, size_t *pcbDecryptedAlloced, PRTERRINFO pErrInfo)
185{
186 /*
187 * Initialize return values.
188 */
189 *ppbDecrypted = NULL;
190 *pcbDecrypted = 0;
191 *pcbDecryptedAlloced = 0;
192
193 /*
194 * This operation requires a password.
195 */
196 if (!pszPassword)
197 return VERR_CR_KEY_ENCRYPTED;
198
199#ifdef IPRT_WITH_OPENSSL /** @todo abstract encryption & decryption. */
200
201 /*
202 * Query the EncryptionAlgorithm bytes so we can construction a X509_ALGOR
203 * for use in PKCS12_pbe_crypt.
204 */
205 void *pvAlgoFree = NULL;
206 const uint8_t *pbAlgoRaw = NULL;
207 uint32_t cbAlgoRaw = 0;
208 int rc = RTAsn1EncodeQueryRawBits(&pEncryptedKey->EncryptionAlgorithm.SeqCore.Asn1Core,
209 &pbAlgoRaw, &cbAlgoRaw, &pvAlgoFree, pErrInfo);
210 AssertRCReturn(rc, rc);
211
212 const unsigned char *puchAlgo = pbAlgoRaw;
213 X509_ALGOR *pOsslAlgoRet = NULL;
214 pOsslAlgoRet = d2i_X509_ALGOR(&pOsslAlgoRet, &puchAlgo, cbAlgoRaw);
215
216 RTMemTmpFree(pvAlgoFree);
217 if (pOsslAlgoRet)
218 {
219 /*
220 * Do the decryption (en_de = 0).
221 */
222 int cbDecrypted = 0;
223 unsigned char *puchDecrypted = NULL;
224 puchDecrypted = PKCS12_pbe_crypt(pOsslAlgoRet, pszPassword, (int)strlen(pszPassword),
225 pEncryptedKey->EncryptedData.Asn1Core.uData.puch,
226 (int)pEncryptedKey->EncryptedData.Asn1Core.cb,
227 &puchDecrypted, &cbDecrypted, 0 /*en_de*/);
228 if (puchDecrypted)
229 {
230 /*
231 * Transfer to a safer buffer and carefully wipe the OpenSSL buffer.
232 */
233 uint8_t *pbFinal = (uint8_t *)RTMemSaferAllocZ(cbDecrypted);
234 if (pbFinal)
235 {
236 memcpy(pbFinal, puchDecrypted, cbDecrypted);
237 *ppbDecrypted = pbFinal;
238 *pcbDecrypted = cbDecrypted;
239 *pcbDecryptedAlloced = cbDecrypted;
240 rc = VINF_SUCCESS;
241 }
242 else
243 rc = VERR_NO_MEMORY;
244 RTMemWipeThoroughly(puchDecrypted, cbDecrypted, 3);
245 OPENSSL_free(puchDecrypted);
246 }
247 else
248 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
249 "Incorrect password? d2i_X509_ALGOR failed (%u)", ERR_get_error());
250 X509_ALGOR_free(pOsslAlgoRet);
251 }
252 else
253 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED /* close enough */,
254 "d2i_X509_ALGOR failed (%u)", ERR_get_error());
255 return rc;
256
257#else
258 RT_NOREF(pEncryptedKey, pszPassword, pErrInfo);
259 return VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED;
260#endif
261}
262
263
264/**
265 * Decrypts a PEM message.
266 *
267 * @returns IPRT status code
268 * @param pszDekInfo The decryption info. See RFC-1421 section 4.6.1.3
269 * as well as RFC-1423).
270 * @param pszPassword The password to use to decrypt the key text.
271 * @param pbEncrypted The encrypted key text.
272 * @param cbEncrypted The size of the encrypted text.
273 * @param ppbDecrypted Where to return the decrypted message. Free using RTMemSaferFree.
274 * @param pcbDecrypted Where to return the length of the decrypted message.
275 * @param pcbDecryptedAlloced Where to return the allocation size.
276 * @param pErrInfo Where to return additional error information.
277 */
278static int rtCrKeyDecryptPemMessage(const char *pszDekInfo, const char *pszPassword, uint8_t *pbEncrypted, size_t cbEncrypted,
279 uint8_t **ppbDecrypted, size_t *pcbDecrypted, size_t *pcbDecryptedAlloced, PRTERRINFO pErrInfo)
280{
281 /*
282 * Initialize return values.
283 */
284 *ppbDecrypted = NULL;
285 *pcbDecrypted = 0;
286 *pcbDecryptedAlloced = 0;
287
288 /*
289 * Parse the DEK-Info.
290 */
291 if (!pszDekInfo)
292 return VERR_CR_KEY_NO_DEK_INFO;
293
294 /* Find the end of the algorithm */
295 const char *pszParams = strchr(pszDekInfo, ',');
296 if (!pszParams)
297 pszParams = strchr(pszDekInfo, '\0');
298 size_t cchAlgo = pszParams - pszDekInfo;
299 while (cchAlgo > 0 && RT_C_IS_SPACE(pszDekInfo[cchAlgo - 1]))
300 cchAlgo--;
301
302 /* Copy it out and zero terminating it. */
303 char szAlgo[256];
304 if (cchAlgo >= sizeof(szAlgo))
305 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DEK_INFO_TOO_LONG, "Algorithms list is too long (%s)", pszDekInfo);
306 memcpy(szAlgo, pszDekInfo, cchAlgo);
307 szAlgo[cchAlgo] = '\0';
308
309 /* Parameters. */
310 pszParams = RTStrStripL(*pszParams == ',' ? pszParams + 1 : pszParams);
311 size_t const cchParams = strlen(pszParams);
312
313 /*
314 * Do we support the cipher?
315 */
316#ifdef IPRT_WITH_OPENSSL /** @todo abstract encryption & decryption. */
317 const EVP_CIPHER *pCipher = EVP_get_cipherbyname(szAlgo);
318 if (!pCipher)
319 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_UNSUPPORTED_CIPHER, "Unknown key cipher: %s (params: %s)", szAlgo, pszParams);
320
321 /* Decode the initialization vector if one is required. */
322 uint8_t *pbInitVector = NULL;
323 int const cbInitVector = EVP_CIPHER_iv_length(pCipher);
324 if (cbInitVector > 0)
325 {
326 if (*pszParams == '\0')
327 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_MISSING_CIPHER_PARAMS,
328 "Cipher '%s' expected %u bytes initialization vector, none found", cbInitVector, szAlgo);
329 if ((size_t)cbInitVector > cchParams / 2)
330 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_TOO_SHORT_CIPHER_IV,
331 "Too short initialization vector for '%s', expected %u chars found only %u: %s",
332 szAlgo, cbInitVector * 2, cchParams, pszParams);
333 pbInitVector = (uint8_t *)alloca(cbInitVector);
334 int rc = RTStrConvertHexBytes(pszParams, pbInitVector, cbInitVector, 0 /*fFlags*/);
335 if ( RT_FAILURE(rc)
336 && rc != VERR_BUFFER_OVERFLOW /* openssl ignores this condition */)
337 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_MALFORMED_CIPHER_IV,
338 "Malformed initialization vector for '%s': %s (rc=%Rrc)", szAlgo, pszParams, rc);
339 }
340 else if (*pszParams != '\0')
341 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS,
342 "Cipher '%s' expected no parameters, found: %s", szAlgo, pszParams);
343
344 /*
345 * Do we have a password? If so try decrypt the key.
346 */
347 if (!pszPassword)
348 return VERR_CR_KEY_ENCRYPTED;
349
350 unsigned char abKey[EVP_MAX_KEY_LENGTH * 2];
351 int cbKey = EVP_BytesToKey(pCipher, EVP_md5(), pbInitVector, (unsigned char const *)pszPassword, (int)strlen(pszPassword),
352 1, abKey, NULL);
353 if (!cbKey)
354 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_PASSWORD_ENCODING, "EVP_BytesToKey failed to encode password");
355
356 EVP_CIPHER_CTX *pCipherCtx = EVP_CIPHER_CTX_new();
357 if (!pCipherCtx)
358 return VERR_NO_MEMORY;
359
360 int rc;
361 if (EVP_DecryptInit_ex(pCipherCtx, pCipher, NULL /*pEngine*/, abKey, pbInitVector))
362 {
363 size_t cbDecryptedAlloced = cbEncrypted;
364 int cbDecrypted = (int)cbDecryptedAlloced;
365 uint8_t *pbDecrypted = (uint8_t *)RTMemSaferAllocZ(cbDecryptedAlloced);
366 if (pbDecrypted)
367 {
368 if (EVP_DecryptUpdate(pCipherCtx, pbDecrypted, &cbDecrypted, pbEncrypted, (int)cbEncrypted))
369 {
370 int cbFinal = (int)cbDecryptedAlloced - cbDecrypted;
371 if (EVP_DecryptFinal_ex(pCipherCtx, &pbDecrypted[cbDecrypted], &cbFinal))
372 {
373 cbDecrypted += cbFinal;
374 Assert((size_t)cbDecrypted <= cbDecryptedAlloced);
375
376 /*
377 * Done! Just set the return values.
378 */
379 *pcbDecrypted = cbDecrypted;
380 *pcbDecryptedAlloced = cbDecryptedAlloced;
381 *ppbDecrypted = pbDecrypted;
382 pbDecrypted = NULL;
383 rc = VINF_CR_KEY_WAS_DECRYPTED;
384 }
385 else
386 rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
387 "Incorrect password? EVP_DecryptFinal_ex failed for %s", pszDekInfo);
388 }
389 else
390 rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
391 "Incorrect password? EVP_DecryptUpdate failed for %s", pszDekInfo);
392 if (pbDecrypted)
393 RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
394 }
395 else
396 rc = VERR_NO_MEMORY;
397 }
398 else
399 rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR, "EVP_DecryptInit_ex failed for %s", pszDekInfo);
400 EVP_CIPHER_CTX_free(pCipherCtx);
401 return rc;
402#else
403 RT_NOREF(pbEncrypted, cbEncrypted, pszPassword, pErrInfo, cchParams);
404 return VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED;
405#endif
406}
407
408
409RTDECL(int) RTCrKeyCreateFromPemSection(PRTCRKEY phKey, PCRTCRPEMSECTION pSection, uint32_t fFlags, const char *pszPassword,
410 PRTERRINFO pErrInfo, const char *pszErrorTag)
411{
412 AssertReturn(!(fFlags & (~RTCRKEYFROM_F_VALID_MASK | RTCRKEYFROM_F_ONLY_PEM)), VERR_INVALID_FLAGS);
413
414 AssertPtrReturn(phKey, VERR_INVALID_POINTER);
415 *phKey = NIL_RTCRKEY;
416 AssertPtrReturn(pSection, VERR_INVALID_POINTER);
417 NOREF(pszPassword);
418
419 /*
420 * If the source is PEM section, try identify the format from the markers.
421 */
422 enum
423 {
424 kKeyFormat_Unknown = 0,
425 kKeyFormat_RsaPrivateKey,
426 kKeyFormat_RsaEncryptedPrivateKey,
427 kKeyFormat_RsaPublicKey,
428 kKeyFormat_SubjectPublicKeyInfo,
429 kKeyFormat_PrivateKeyInfo,
430 kKeyFormat_EncryptedPrivateKeyInfo
431 } enmFormat = kKeyFormat_Unknown;
432 const char *pszDekInfo = NULL;
433 PCRTCRPEMMARKER pMarker = pSection->pMarker;
434 if (pMarker)
435 {
436 if ( pMarker->cWords == 3
437 && strcmp(pMarker->paWords[0].pszWord, "RSA") == 0
438 && strcmp(pMarker->paWords[2].pszWord, "KEY") == 0)
439 {
440 if (strcmp(pMarker->paWords[1].pszWord, "PUBLIC") == 0)
441 enmFormat = kKeyFormat_RsaPublicKey;
442 else if (strcmp(pMarker->paWords[1].pszWord, "PRIVATE") == 0)
443 {
444 enmFormat = kKeyFormat_RsaPrivateKey;
445
446 /* RSA PRIVATE KEY encryption is advertised thru PEM header fields.
447 We need the DEK field to decrypt the message (see RFC-1421 4.6.1.3). */
448 for (PCRTCRPEMFIELD pField = pSection->pFieldHead; pField; pField = pField->pNext)
449 {
450 if ( pField->cchName == sizeof("Proc-Type") - 1
451 && pField->cchValue >= sizeof("4,ENCRYPTED") - 1
452 && memcmp(pField->szName, RT_STR_TUPLE("Proc-Type")) == 0)
453 {
454 const char *pszValue = pField->pszValue;
455 if (*pszValue == '4')
456 {
457 do
458 pszValue++;
459 while (RT_C_IS_SPACE(*pszValue) || RT_C_IS_PUNCT(*pszValue));
460 if (strcmp(pszValue, "ENCRYPTED") == 0)
461 enmFormat = kKeyFormat_RsaEncryptedPrivateKey;
462 }
463 }
464 else if ( pField->cchName == sizeof("DEK-Info") - 1
465 && pField->cchValue > 0
466 && !pszDekInfo)
467 pszDekInfo = pField->pszValue;
468 }
469 }
470 else
471 AssertFailed();
472 }
473 else if ( pMarker->cWords == 2
474 && strcmp(pMarker->paWords[1].pszWord, "KEY") == 0)
475 {
476 if (strcmp(pMarker->paWords[0].pszWord, "PUBLIC") == 0)
477 enmFormat = kKeyFormat_SubjectPublicKeyInfo;
478 else if (strcmp(pMarker->paWords[0].pszWord, "PRIVATE") == 0)
479 enmFormat = kKeyFormat_PrivateKeyInfo;
480 else
481 AssertFailed();
482 }
483 else if ( pMarker->cWords == 3
484 && strcmp(pMarker->paWords[0].pszWord, "ENCRYPTED") == 0
485 && strcmp(pMarker->paWords[1].pszWord, "PRIVATE") == 0
486 && strcmp(pMarker->paWords[2].pszWord, "KEY") == 0)
487 enmFormat = kKeyFormat_EncryptedPrivateKeyInfo;
488 else
489 AssertFailed();
490 }
491
492 /*
493 * Try guess the format from the binary data if needed.
494 */
495 RTASN1CURSORPRIMARY PrimaryCursor;
496 if ( enmFormat == kKeyFormat_Unknown
497 && pSection->cbData > 10)
498 {
499 RTAsn1CursorInitPrimary(&PrimaryCursor, pSection->pbData, (uint32_t)pSection->cbData,
500 pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "probing/0");
501
502 /*
503 * First the must be a sequence.
504 */
505 RTASN1CORE Tag;
506 int rc = RTAsn1CursorReadHdr(&PrimaryCursor.Cursor, &Tag, "#1");
507 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_SEQUENCE)
508 {
509 RTASN1CURSOR Cursor2;
510 RTAsn1CursorInitSubFromCore(&PrimaryCursor.Cursor, &Tag, &Cursor2, "probing/1");
511 rc = RTAsn1CursorReadHdr(&Cursor2, &Tag, "#2");
512
513 /*
514 * SEQUENCE SubjectPublicKeyInfo.Algorithm?
515 */
516 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_SEQUENCE)
517 {
518 RTASN1CURSOR Cursor3;
519 RTAsn1CursorInitSubFromCore(&Cursor2, &Tag, &Cursor3, "probing/2");
520 rc = RTAsn1CursorReadHdr(&Cursor3, &Tag, "#3");
521
522 /* SEQUENCE SubjectPublicKeyInfo.Algorithm.Algorithm? */
523 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_OID)
524 enmFormat = kKeyFormat_SubjectPublicKeyInfo;
525 }
526 /*
527 * INTEGER PrivateKeyInfo.Version?
528 * INTEGER RsaPublicKey.Modulus?
529 * INTEGER RsaPrivateKey.Version?
530 */
531 else if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_INTEGER)
532 {
533 rc = RTAsn1CursorReadHdr(RTAsn1CursorSkip(&Cursor2, Tag.cb), &Tag, "#4");
534
535 /* OBJECT PrivateKeyInfo.privateKeyAlgorithm? */
536 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_OID)
537 enmFormat = kKeyFormat_PrivateKeyInfo;
538 /* INTEGER RsaPublicKey.PublicExponent?
539 INTEGER RsaPrivateKey.Modulus? */
540 else if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_INTEGER)
541 {
542 /* RsaPublicKey.PublicExponent is at the end. */
543 if (RTAsn1CursorIsEnd(&Cursor2))
544 enmFormat = kKeyFormat_RsaPublicKey;
545 else
546 {
547 /* Check for INTEGER RsaPrivateKey.PublicExponent nad PrivateExponent before concluding. */
548 rc = RTAsn1CursorReadHdr(RTAsn1CursorSkip(&Cursor2, Tag.cb), &Tag, "#5");
549 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_INTEGER)
550 {
551 rc = RTAsn1CursorReadHdr(RTAsn1CursorSkip(&Cursor2, Tag.cb), &Tag, "#6");
552 if (RT_SUCCESS(rc) && Tag.uTag == ASN1_TAG_INTEGER)
553 enmFormat = kKeyFormat_RsaPrivateKey;
554 }
555 }
556 }
557 }
558 }
559 }
560
561 if (enmFormat == kKeyFormat_Unknown)
562 return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_UNKNOWN_TYPE,
563 "Unable to identify the key format (%.*Rhxs)", RT_MIN(16, pSection->cbData), pSection->pbData);
564
565 /*
566 * Do the reading.
567 */
568 int rc;
569 switch (enmFormat)
570 {
571 case kKeyFormat_RsaPublicKey:
572 rc = rtCrKeyCreateRsaPublic(phKey, pSection->pbData, (uint32_t)pSection->cbData, pErrInfo, pszErrorTag);
573 break;
574
575 case kKeyFormat_RsaPrivateKey:
576 rc = rtCrKeyCreateRsaPrivate(phKey, pSection->pbData, (uint32_t)pSection->cbData, pErrInfo, pszErrorTag);
577 break;
578
579 case kKeyFormat_RsaEncryptedPrivateKey:
580 {
581 uint8_t *pbDecrypted = NULL;
582 size_t cbDecrypted = 0;
583 size_t cbDecryptedAlloced = 0;
584 rc = rtCrKeyDecryptPemMessage(pszDekInfo, pszPassword, pSection->pbData, pSection->cbData,
585 &pbDecrypted, &cbDecrypted, &cbDecryptedAlloced, pErrInfo);
586 if (RT_SUCCESS(rc))
587 {
588 int rc2 = rtCrKeyCreateRsaPrivate(phKey, pbDecrypted, (uint32_t)cbDecrypted, pErrInfo, pszErrorTag);
589 if (rc2 != VINF_SUCCESS)
590 rc = rc2;
591 RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
592 }
593 break;
594 }
595
596 case kKeyFormat_SubjectPublicKeyInfo:
597 {
598 RTAsn1CursorInitPrimary(&PrimaryCursor, pSection->pbData, (uint32_t)pSection->cbData,
599 pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, pszErrorTag);
600 RTCRX509SUBJECTPUBLICKEYINFO SubjectPubKeyInfo;
601 RT_ZERO(SubjectPubKeyInfo);
602 rc = RTCrX509SubjectPublicKeyInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &SubjectPubKeyInfo, "SubjectPubKeyInfo");
603 if (RT_SUCCESS(rc))
604 {
605 rc = RTCrKeyCreateFromSubjectPublicKeyInfo(phKey, &SubjectPubKeyInfo, pErrInfo, pszErrorTag);
606 RTCrX509SubjectPublicKeyInfo_Delete(&SubjectPubKeyInfo);
607 }
608 break;
609 }
610
611 case kKeyFormat_PrivateKeyInfo:
612 rc = rtCrKeyCreateFromPrivateKeyInfo(phKey, &PrimaryCursor, pSection->pbData, pSection->cbData, pErrInfo, pszErrorTag);
613 break;
614
615 case kKeyFormat_EncryptedPrivateKeyInfo:
616 {
617 RTAsn1CursorInitPrimary(&PrimaryCursor, pSection->pbData, (uint32_t)pSection->cbData,
618 pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, pszErrorTag);
619 RTCRPKCS8ENCRYPTEDPRIVATEKEYINFO EncryptedPrivateKeyInfo;
620 RT_ZERO(EncryptedPrivateKeyInfo);
621 rc = RTCrPkcs8EncryptedPrivateKeyInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &EncryptedPrivateKeyInfo,
622 pszErrorTag ? pszErrorTag : "EncryptedPrivateKeyInfo");
623 if (RT_SUCCESS(rc))
624 {
625 uint8_t *pbDecrypted = NULL;
626 size_t cbDecrypted = 0;
627 size_t cbDecryptedAlloced = 0;
628 rc = rtCrKeyDecryptPkcs8Info(&EncryptedPrivateKeyInfo, pszPassword,
629 &pbDecrypted, &cbDecrypted, &cbDecryptedAlloced, pErrInfo);
630 if (RT_SUCCESS(rc))
631 {
632 rc = rtCrKeyCreateFromPrivateKeyInfo(phKey, &PrimaryCursor, pbDecrypted, cbDecrypted, pErrInfo, pszErrorTag);
633
634 RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
635 }
636 RTCrPkcs8EncryptedPrivateKeyInfo_Delete(&EncryptedPrivateKeyInfo);
637 }
638 break;
639 }
640
641 default:
642 AssertFailedStmt(rc = VERR_INTERNAL_ERROR_4);
643 }
644 return rc;
645}
646
647
648RTDECL(int) RTCrKeyCreateFromBuffer(PRTCRKEY phKey, uint32_t fFlags, void const *pvSrc, size_t cbSrc, const char *pszPassword,
649 PRTERRINFO pErrInfo, const char *pszErrorTag)
650{
651 AssertReturn(!(fFlags & ~RTCRKEYFROM_F_VALID_MASK), VERR_INVALID_FLAGS);
652 PCRTCRPEMSECTION pSectionHead;
653 int rc = RTCrPemParseContent(pvSrc, cbSrc, fFlags, g_aRTCrKeyAllMarkers, g_cRTCrKeyAllMarkers, &pSectionHead, pErrInfo);
654 if (RT_SUCCESS(rc))
655 {
656 if (pSectionHead)
657 {
658 rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags & ~RTCRKEYFROM_F_ONLY_PEM, pszPassword,
659 pErrInfo, pszErrorTag);
660 RTCrPemFreeSections(pSectionHead);
661 }
662 else
663 rc = rc != VINF_SUCCESS ? -rc : VERR_INTERNAL_ERROR_2;
664 }
665 return rc;
666}
667
668
669RTDECL(int) RTCrKeyCreateFromFile(PRTCRKEY phKey, uint32_t fFlags, const char *pszFilename,
670 const char *pszPassword, PRTERRINFO pErrInfo)
671{
672 AssertReturn(!(fFlags & ~RTCRKEYFROM_F_VALID_MASK), VERR_INVALID_FLAGS);
673 PCRTCRPEMSECTION pSectionHead;
674 int rc = RTCrPemReadFile(pszFilename, fFlags, g_aRTCrKeyAllMarkers, g_cRTCrKeyAllMarkers, &pSectionHead, pErrInfo);
675 if (RT_SUCCESS(rc))
676 {
677 if (pSectionHead)
678 {
679 rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags & ~RTCRKEYFROM_F_ONLY_PEM, pszPassword,
680 pErrInfo, RTPathFilename(pszFilename));
681 RTCrPemFreeSections(pSectionHead);
682 }
683 else
684 rc = rc != VINF_SUCCESS ? -rc : VERR_INTERNAL_ERROR_2;
685 }
686 return rc;
687}
688
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette