VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/key.cpp@ 73665

Last change on this file since 73665 was 73665, checked in by vboxsync, 6 years ago

IPRT,SUP,Main: Working on new crypto key handling and rsa signing. bugref:9152

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1/* $Id: key.cpp 73665 2018-08-14 17:49:23Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Cryptographic Keys.
4 */
5
6/*
7 * Copyright (C) 2006-2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/crypto/key.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/mem.h>
38#include <iprt/memsafer.h>
39#include <iprt/string.h>
40#include <iprt/crypto/rsa.h>
41#include <iprt/crypto/pkix.h>
42
43#include "internal/magics.h"
44#include "key-internal.h"
45
46
47/**
48 * Internal crypto key instance creator.
49 *
50 * This does most of the common work, caller does the 'u' and cBits jobs.
51 *
52 * @returns IPRT status code.
53 * @param ppThis Where to return the key instance.
54 * @param enmType The key type.
55 * @param fFlags The key flags.
56 * @param pvEncoded The encoded key bits.
57 * @param cbEncoded The size of the encoded key bits (in bytes).
58 */
59DECLHIDDEN(int) rtCrKeyCreateWorker(PRTCRKEYINT *ppThis, RTCRKEYTYPE enmType, uint32_t fFlags,
60 void const *pvEncoded, uint32_t cbEncoded)
61{
62 PRTCRKEYINT pThis = (PRTCRKEYINT)RTMemAllocZ(sizeof(*pThis) + (fFlags & RTCRKEYINT_F_SENSITIVE ? 0 : cbEncoded));
63 if (pThis)
64 {
65 pThis->enmType = enmType;
66 pThis->fFlags = fFlags;
67#if defined(IPRT_WITH_OPENSSL)
68 pThis->cbEncoded = cbEncoded;
69 if (!(fFlags & RTCRKEYINT_F_SENSITIVE))
70 pThis->pbEncoded = (uint8_t *)(pThis + 1);
71 else
72 {
73 pThis->pbEncoded = (uint8_t *)RTMemSaferAllocZ(cbEncoded);
74 if (!pThis->pbEncoded)
75 {
76 RTMemFree(pThis);
77 return VERR_NO_MEMORY;
78 }
79 }
80 memcpy(pThis->pbEncoded, pvEncoded, cbEncoded);
81#else
82 RT_NOREF(pvEncoded, cbEncoded);
83#endif
84 pThis->cRefs = 1;
85 pThis->u32Magic = RTCRKEYINT_MAGIC;
86 *ppThis = pThis;
87 return VINF_SUCCESS;
88 }
89 return VERR_NO_MEMORY;
90}
91
92
93/**
94 * Creates an RSA public key from a DER encoded RTCRRSAPUBLICKEY blob.
95 *
96 * @returns IPRT status code.
97 * @param phKey Where to return the key handle.
98 * @param pvKeyBits The DER encoded RTCRRSAPUBLICKEY blob.
99 * @param cbKeyBits The size of the blob.
100 * @param pErrInfo Where to supply addition error details. Optional.
101 * @param pszErrorTag Error tag. Optional.
102 */
103DECLHIDDEN(int) rtCrKeyCreateRsaPublic(PRTCRKEY phKey, const void *pvKeyBits, uint32_t cbKeyBits,
104 PRTERRINFO pErrInfo, const char *pszErrorTag)
105{
106 /*
107 * Decode the key data first since that's what's most likely to fail here.
108 */
109 RTASN1CURSORPRIMARY PrimaryCursor;
110 RTAsn1CursorInitPrimary(&PrimaryCursor, pvKeyBits, cbKeyBits, pErrInfo, &g_RTAsn1DefaultAllocator,
111 RTASN1CURSOR_FLAGS_DER, pszErrorTag ? pszErrorTag : "rsa");
112 RTCRRSAPUBLICKEY PublicKey;
113 RT_ZERO(PublicKey);
114 int rc = RTCrRsaPublicKey_DecodeAsn1(&PrimaryCursor.Cursor, 0, &PublicKey, pszErrorTag ? pszErrorTag : "PublicKey");
115 if (RT_SUCCESS(rc))
116 {
117 /*
118 * Create a key instance for it.
119 */
120 PRTCRKEYINT pThis;
121 rc = rtCrKeyCreateWorker(&pThis, RTCRKEYTYPE_RSA_PUBLIC, RTCRKEYINT_F_PUBLIC, pvKeyBits, cbKeyBits);
122 if (RT_SUCCESS(rc))
123 {
124 rc = RTAsn1Integer_ToBigNum(&PublicKey.Modulus, &pThis->u.RsaPublic.Modulus, 0);
125 if (RT_SUCCESS(rc))
126 {
127 pThis->cBits = RTBigNumBitWidth(&pThis->u.RsaPublic.Modulus);
128 rc = RTAsn1Integer_ToBigNum(&PublicKey.PublicExponent, &pThis->u.RsaPublic.Exponent, 0);
129 if (RT_SUCCESS(rc))
130 {
131
132 /* Done. */
133 RTAsn1VtDelete(&PublicKey.SeqCore.Asn1Core);
134 *phKey = pThis;
135 return VINF_SUCCESS;
136 }
137 }
138 RTCrKeyRelease(pThis);
139 }
140 RTAsn1VtDelete(&PublicKey.SeqCore.Asn1Core);
141 }
142 *phKey = NIL_RTCRKEY;
143 return rc;
144}
145
146
147RTDECL(int) RTCrKeyCreateFromPublicAlgorithmAndBits(PRTCRKEY phKey, PCRTASN1OBJID pAlgorithm, PCRTASN1BITSTRING pPublicKey,
148 PRTERRINFO pErrInfo, const char *pszErrorTag)
149{
150 /*
151 * Validate input.
152 */
153 AssertPtrReturn(phKey, VERR_INVALID_POINTER);
154 *phKey = NIL_RTCRKEY;
155
156 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
157 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_PARAMETER);
158
159 AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER);
160 AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_PARAMETER);
161
162 /*
163 * Taking a weird shortcut here.
164 */
165 PCRTCRPKIXSIGNATUREDESC pDesc = RTCrPkixSignatureFindByObjId(pAlgorithm, NULL);
166 if (pDesc && strcmp(pDesc->pszObjId, RTCRX509ALGORITHMIDENTIFIERID_RSA) == 0)
167 return rtCrKeyCreateRsaPublic(phKey,
168 RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey),
169 RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey),
170 pErrInfo, pszErrorTag);
171 Assert(pDesc == NULL);
172 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN, "oid=%s", pAlgorithm->szObjId);
173}
174
175
176RTDECL(int) RTCrKeyCreateFromSubjectPublicKeyInfo(PRTCRKEY phKey, struct RTCRX509SUBJECTPUBLICKEYINFO const *pSrc,
177 PRTERRINFO pErrInfo, const char *pszErrorTag)
178{
179 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
180 AssertReturn(RTCrX509SubjectPublicKeyInfo_IsPresent(pSrc), VERR_INVALID_PARAMETER);
181 return RTCrKeyCreateFromPublicAlgorithmAndBits(phKey, &pSrc->Algorithm.Algorithm, &pSrc->SubjectPublicKey,
182 pErrInfo, pszErrorTag);
183}
184
185
186/**
187 * Creates an RSA private key from a DER encoded RTCRRSAPRIVATEKEY blob.
188 *
189 * @returns IPRT status code.
190 * @param phKey Where to return the key handle.
191 * @param pvKeyBits The DER encoded RTCRRSAPRIVATEKEY blob.
192 * @param cbKeyBits The size of the blob.
193 * @param pErrInfo Where to supply addition error details. Optional.
194 * @param pszErrorTag Error tag. Optional.
195 */
196DECLHIDDEN(int) rtCrKeyCreateRsaPrivate(PRTCRKEY phKey, const void *pvKeyBits, uint32_t cbKeyBits,
197 PRTERRINFO pErrInfo, const char *pszErrorTag)
198{
199 /*
200 * Decode the key data first since that's what's most likely to fail here.
201 */
202 RTASN1CURSORPRIMARY PrimaryCursor;
203 RTAsn1CursorInitPrimary(&PrimaryCursor, pvKeyBits, cbKeyBits, pErrInfo, &g_RTAsn1SaferAllocator,
204 RTASN1CURSOR_FLAGS_DER, pszErrorTag ? pszErrorTag : "rsa");
205 RTCRRSAPRIVATEKEY PrivateKey;
206 RT_ZERO(PrivateKey);
207 int rc = RTCrRsaPrivateKey_DecodeAsn1(&PrimaryCursor.Cursor, 0, &PrivateKey, pszErrorTag ? pszErrorTag : "PrivateKey");
208 if (RT_SUCCESS(rc))
209 {
210 /*
211 * Create a key instance for it.
212 */
213 PRTCRKEYINT pThis;
214 rc = rtCrKeyCreateWorker(&pThis, RTCRKEYTYPE_RSA_PRIVATE, RTCRKEYINT_F_PRIVATE | RTCRKEYINT_F_SENSITIVE,
215 pvKeyBits, cbKeyBits);
216 if (RT_SUCCESS(rc))
217 {
218 rc = RTAsn1Integer_ToBigNum(&PrivateKey.Modulus, &pThis->u.RsaPrivate.Modulus, 0);
219 if (RT_SUCCESS(rc))
220 {
221 pThis->cBits = RTBigNumBitWidth(&pThis->u.RsaPrivate.Modulus);
222 rc = RTAsn1Integer_ToBigNum(&PrivateKey.PrivateExponent, &pThis->u.RsaPrivate.PrivateExponent, 0);
223 if (RT_SUCCESS(rc))
224 {
225 rc = RTAsn1Integer_ToBigNum(&PrivateKey.PublicExponent, &pThis->u.RsaPrivate.PublicExponent, 0);
226 if (RT_SUCCESS(rc))
227 {
228 /* Done. */
229 RTAsn1VtDelete(&PrivateKey.SeqCore.Asn1Core);
230 RTMemWipeThoroughly(&PrivateKey, sizeof(PrivateKey), 3);
231 *phKey = pThis;
232 return VINF_SUCCESS;
233 }
234 }
235 }
236 RTCrKeyRelease(pThis);
237 }
238 RTAsn1VtDelete(&PrivateKey.SeqCore.Asn1Core);
239 RTMemWipeThoroughly(&PrivateKey, sizeof(PrivateKey), 3);
240 }
241 *phKey = NIL_RTCRKEY;
242 return rc;
243}
244
245
246RTDECL(uint32_t) RTCrKeyRetain(RTCRKEY hKey)
247{
248 PRTCRKEYINT pThis = hKey;
249 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, UINT32_MAX);
250
251 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
252 AssertMsg(cRefs > 1 && cRefs < 1024, ("%#x\n", cRefs));
253 return cRefs;
254}
255
256
257/**
258 * Destructor.
259 *
260 * @returns 0
261 * @param pThis The key to destroy.
262 */
263static int rtCrKeyDestroy(PRTCRKEYINT pThis)
264{
265 /* Invalidate the object. */
266 pThis->u32Magic = ~RTCRKEYINT_MAGIC;
267
268 /* Type specific cleanup. */
269 switch (pThis->enmType)
270 {
271 case RTCRKEYTYPE_RSA_PUBLIC:
272 RTBigNumDestroy(&pThis->u.RsaPublic.Modulus);
273 RTBigNumDestroy(&pThis->u.RsaPublic.Exponent);
274 break;
275
276 case RTCRKEYTYPE_RSA_PRIVATE:
277 RTBigNumDestroy(&pThis->u.RsaPrivate.Modulus);
278 RTBigNumDestroy(&pThis->u.RsaPrivate.PrivateExponent);
279 RTBigNumDestroy(&pThis->u.RsaPrivate.PublicExponent);
280 break;
281
282 case RTCRKEYTYPE_INVALID:
283 case RTCRKEYTYPE_END:
284 case RTCRKEYTYPE_32BIT_HACK:
285 AssertFailed();
286 }
287 pThis->enmType = RTCRKEYTYPE_INVALID;
288
289#if defined(IPRT_WITH_OPENSSL)
290 /* Free the encoded form if sensitive (otherwise it follows pThis). */
291 if (pThis->pbEncoded)
292 {
293 if (pThis->fFlags & RTCRKEYINT_F_SENSITIVE)
294 RTMemSaferFree((uint8_t *)pThis->pbEncoded, pThis->cbEncoded);
295 else
296 Assert(pThis->pbEncoded == (uint8_t *)(pThis + 1));
297 pThis->pbEncoded = NULL;
298 }
299#endif
300
301 /* Finally, free the key object itself. */
302 RTMemFree(pThis);
303 return 0;
304}
305
306
307RTDECL(uint32_t) RTCrKeyRelease(RTCRKEY hKey)
308{
309 if (hKey == NIL_RTCRKEY)
310 return 0;
311 PRTCRKEYINT pThis = hKey;
312 AssertPtrReturn(pThis, UINT32_MAX);
313 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, UINT32_MAX);
314
315 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
316 AssertMsg(cRefs < 1024, ("%#x\n", cRefs));
317 if (cRefs != 0)
318 return cRefs;
319 return rtCrKeyDestroy(pThis);
320}
321
322
323RTDECL(RTCRKEYTYPE) RTCrKeyGetType(RTCRKEY hKey)
324{
325 PRTCRKEYINT pThis = hKey;
326 AssertPtrReturn(pThis, RTCRKEYTYPE_INVALID);
327 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, RTCRKEYTYPE_INVALID);
328 return pThis->enmType;
329}
330
331
332RTDECL(bool) RTCrKeyHasPrivatePart(RTCRKEY hKey)
333{
334 PRTCRKEYINT pThis = hKey;
335 AssertPtrReturn(pThis, false);
336 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, false);
337 return RT_BOOL(pThis->fFlags & RTCRKEYINT_F_PRIVATE);
338}
339
340
341RTDECL(bool) RTCrKeyHasPublicPart(RTCRKEY hKey)
342{
343 PRTCRKEYINT pThis = hKey;
344 AssertPtrReturn(pThis, false);
345 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, false);
346 return RT_BOOL(pThis->fFlags & RTCRKEYINT_F_PUBLIC);
347}
348
349
350RTDECL(uint32_t) RTCrKeyGetBitCount(RTCRKEY hKey)
351{
352 PRTCRKEYINT pThis = hKey;
353 AssertPtrReturn(pThis, 0);
354 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, 0);
355 return pThis->cBits;
356}
357
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