VirtualBox

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

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

IPRT/rest: Started implementing http-signatures for oci. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/* $Id: key.cpp 74052 2018-09-03 20:09:45Z 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 AssertPtrReturn(pThis, UINT32_MAX);
250 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, UINT32_MAX);
251
252 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
253 AssertMsg(cRefs > 1 && cRefs < 1024, ("%#x\n", cRefs));
254 return cRefs;
255}
256
257
258/**
259 * Destructor.
260 *
261 * @returns 0
262 * @param pThis The key to destroy.
263 */
264static int rtCrKeyDestroy(PRTCRKEYINT pThis)
265{
266 /* Invalidate the object. */
267 pThis->u32Magic = ~RTCRKEYINT_MAGIC;
268
269 /* Type specific cleanup. */
270 switch (pThis->enmType)
271 {
272 case RTCRKEYTYPE_RSA_PUBLIC:
273 RTBigNumDestroy(&pThis->u.RsaPublic.Modulus);
274 RTBigNumDestroy(&pThis->u.RsaPublic.Exponent);
275 break;
276
277 case RTCRKEYTYPE_RSA_PRIVATE:
278 RTBigNumDestroy(&pThis->u.RsaPrivate.Modulus);
279 RTBigNumDestroy(&pThis->u.RsaPrivate.PrivateExponent);
280 RTBigNumDestroy(&pThis->u.RsaPrivate.PublicExponent);
281 break;
282
283 case RTCRKEYTYPE_INVALID:
284 case RTCRKEYTYPE_END:
285 case RTCRKEYTYPE_32BIT_HACK:
286 AssertFailed();
287 }
288 pThis->enmType = RTCRKEYTYPE_INVALID;
289
290#if defined(IPRT_WITH_OPENSSL)
291 /* Free the encoded form if sensitive (otherwise it follows pThis). */
292 if (pThis->pbEncoded)
293 {
294 if (pThis->fFlags & RTCRKEYINT_F_SENSITIVE)
295 RTMemSaferFree((uint8_t *)pThis->pbEncoded, pThis->cbEncoded);
296 else
297 Assert(pThis->pbEncoded == (uint8_t *)(pThis + 1));
298 pThis->pbEncoded = NULL;
299 }
300#endif
301
302 /* Finally, free the key object itself. */
303 RTMemFree(pThis);
304 return 0;
305}
306
307
308RTDECL(uint32_t) RTCrKeyRelease(RTCRKEY hKey)
309{
310 if (hKey == NIL_RTCRKEY)
311 return 0;
312 PRTCRKEYINT pThis = hKey;
313 AssertPtrReturn(pThis, UINT32_MAX);
314 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, UINT32_MAX);
315
316 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
317 AssertMsg(cRefs < 1024, ("%#x\n", cRefs));
318 if (cRefs != 0)
319 return cRefs;
320 return rtCrKeyDestroy(pThis);
321}
322
323
324RTDECL(RTCRKEYTYPE) RTCrKeyGetType(RTCRKEY hKey)
325{
326 PRTCRKEYINT pThis = hKey;
327 AssertPtrReturn(pThis, RTCRKEYTYPE_INVALID);
328 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, RTCRKEYTYPE_INVALID);
329 return pThis->enmType;
330}
331
332
333RTDECL(bool) RTCrKeyHasPrivatePart(RTCRKEY hKey)
334{
335 PRTCRKEYINT pThis = hKey;
336 AssertPtrReturn(pThis, false);
337 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, false);
338 return RT_BOOL(pThis->fFlags & RTCRKEYINT_F_PRIVATE);
339}
340
341
342RTDECL(bool) RTCrKeyHasPublicPart(RTCRKEY hKey)
343{
344 PRTCRKEYINT pThis = hKey;
345 AssertPtrReturn(pThis, false);
346 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, false);
347 return RT_BOOL(pThis->fFlags & RTCRKEYINT_F_PUBLIC);
348}
349
350
351RTDECL(uint32_t) RTCrKeyGetBitCount(RTCRKEY hKey)
352{
353 PRTCRKEYINT pThis = hKey;
354 AssertPtrReturn(pThis, 0);
355 AssertReturn(pThis->u32Magic == RTCRKEYINT_MAGIC, 0);
356 return pThis->cBits;
357}
358
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