VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/store-inmem.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/* $Id: store-inmem.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - In Memory Cryptographic Certificate Store.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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/store.h>
33
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38
39#include "store-internal.h"
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45/**
46 * A certificate entry in the in-memory store.
47 */
48typedef struct RTCRSTOREINMEMCERT
49{
50 /** The core certificate context. */
51 RTCRCERTCTXINT Core;
52 /** Internal copy of the flag (paranoia). */
53 uint32_t fFlags;
54 /** Decoded data. */
55 union
56 {
57 /** ASN.1 core structure for generic access. */
58 RTASN1CORE Asn1Core;
59 /** The decoded X.509 certificate (RTCRCERTCTX_F_ENC_X509_DER). */
60 RTCRX509CERTIFICATE X509Cert;
61 /** The decoded trust anchor info (RTCRCERTCTX_F_ENC_TAF_DER). */
62 RTCRTAFTRUSTANCHORINFO TaInfo;
63 } u;
64 /** Pointer to the store if still in it (no reference). */
65 struct RTCRSTOREINMEM *pStore;
66 /** The DER encoding of the certificate. */
67 uint8_t abEncoded[1];
68} RTCRSTOREINMEMCERT;
69AssertCompileMembersAtSameOffset(RTCRSTOREINMEMCERT, u.X509Cert.SeqCore.Asn1Core, RTCRSTOREINMEMCERT, u.Asn1Core);
70AssertCompileMembersAtSameOffset(RTCRSTOREINMEMCERT, u.TaInfo.SeqCore.Asn1Core, RTCRSTOREINMEMCERT, u.Asn1Core);
71/** Pointer to an in-memory store certificate entry. */
72typedef RTCRSTOREINMEMCERT *PRTCRSTOREINMEMCERT;
73
74
75/**
76 * The per instance data of a in-memory crypto store.
77 *
78 * Currently we ASSUME we don't need serialization. Add that when needed!
79 */
80typedef struct RTCRSTOREINMEM
81{
82 /** The number of certificates. */
83 uint32_t cCerts;
84 /** The max number of certificates papCerts can store before growing it. */
85 uint32_t cCertsAlloc;
86 /** Array of certificates. */
87 PRTCRSTOREINMEMCERT *papCerts;
88
89 /** Parent store. */
90 RTCRSTORE hParentStore;
91 /** The parent store callback table. */
92 PCRTCRSTOREPROVIDER pParentProvider;
93 /** The parent store provider callback argument. */
94 void *pvParentProvider;
95} RTCRSTOREINMEM;
96/** Pointer to an in-memory crypto store. */
97typedef RTCRSTOREINMEM *PRTCRSTOREINMEM;
98
99
100
101
102static DECLCALLBACK(void) rtCrStoreInMemCertEntry_Dtor(PRTCRCERTCTXINT pCertCtx)
103{
104 PRTCRSTOREINMEMCERT pEntry = (PRTCRSTOREINMEMCERT)pCertCtx;
105 AssertRelease(!pEntry->pStore);
106
107 pEntry->Core.pfnDtor = NULL;
108 RTAsn1VtDelete(&pEntry->u.Asn1Core);
109 RTMemFree(pEntry);
110}
111
112
113/**
114 * Internal method for allocating and initalizing a certificate entry in the
115 * in-memory store.
116 *
117 * @returns IPRT status code.
118 * @param pThis The in-memory store instance.
119 * @param fEnc RTCRCERTCTX_F_ENC_X509_DER or RTCRCERTCTX_F_ENC_TAF_DER.
120 * @param pbSrc The DER encoded X.509 certificate to add.
121 * @param cbSrc The size of the encoded certificate.
122 * @param pErrInfo Where to return extended error info. Optional.
123 * @param ppEntry Where to return the pointer to the new entry.
124 */
125static int rtCrStoreInMemCreateCertEntry(PRTCRSTOREINMEM pThis, uint32_t fEnc, uint8_t const *pbSrc, uint32_t cbSrc,
126 PRTERRINFO pErrInfo, PRTCRSTOREINMEMCERT *ppEntry)
127{
128 int rc;
129 PRTCRSTOREINMEMCERT pEntry = (PRTCRSTOREINMEMCERT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRSTOREINMEMCERT, abEncoded[cbSrc]));
130 if (pEntry)
131 {
132 memcpy(pEntry->abEncoded, pbSrc, cbSrc);
133 pEntry->Core.u32Magic = RTCRCERTCTXINT_MAGIC;
134 pEntry->Core.cRefs = 1;
135 pEntry->Core.pfnDtor = rtCrStoreInMemCertEntry_Dtor;
136 pEntry->Core.Public.fFlags = fEnc;
137 pEntry->Core.Public.cbEncoded = cbSrc;
138 pEntry->Core.Public.pabEncoded = &pEntry->abEncoded[0];
139 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
140 {
141 pEntry->Core.Public.pCert = &pEntry->u.X509Cert;
142 pEntry->Core.Public.pTaInfo = NULL;
143 }
144 else
145 {
146 pEntry->Core.Public.pCert = NULL;
147 pEntry->Core.Public.pTaInfo = &pEntry->u.TaInfo;
148 }
149 pEntry->pStore = pThis;
150
151 RTASN1CURSORPRIMARY Cursor;
152 RTAsn1CursorInitPrimary(&Cursor, &pEntry->abEncoded[0], cbSrc, pErrInfo, &g_RTAsn1DefaultAllocator,
153 RTASN1CURSOR_FLAGS_DER, "InMem");
154 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
155 rc = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &pEntry->u.X509Cert, "Cert");
156 else
157 rc = RTCrTafTrustAnchorInfo_DecodeAsn1(&Cursor.Cursor, 0, &pEntry->u.TaInfo, "TaInfo");
158 if (RT_SUCCESS(rc))
159 {
160 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
161 rc = RTCrX509Certificate_CheckSanity(&pEntry->u.X509Cert, 0, pErrInfo, "Cert");
162 else
163 rc = RTCrTafTrustAnchorInfo_CheckSanity(&pEntry->u.TaInfo, 0, pErrInfo, "TaInfo");
164 if (RT_SUCCESS(rc))
165 {
166 *ppEntry = pEntry;
167 return VINF_SUCCESS;
168 }
169
170 RTAsn1VtDelete(&pEntry->u.Asn1Core);
171 }
172 RTMemFree(pEntry);
173 }
174 else
175 rc = VERR_NO_MEMORY;
176 return rc;
177}
178
179
180/**
181 * Grows the certificate pointer array to at least @a cMin entries.
182 *
183 * @returns IPRT status code.
184 * @param pThis The in-memory store instance.
185 * @param cMin The new minimum store size.
186 */
187static int rtCrStoreInMemGrow(PRTCRSTOREINMEM pThis, uint32_t cMin)
188{
189 AssertReturn(cMin <= _1M, VERR_OUT_OF_RANGE);
190 AssertReturn(cMin > pThis->cCertsAlloc, VERR_INTERNAL_ERROR_3);
191
192 if (cMin < 64)
193 cMin = RT_ALIGN_32(cMin, 8);
194 else
195 cMin = RT_ALIGN_32(cMin, 32);
196
197 void *pv = RTMemRealloc(pThis->papCerts, cMin * sizeof(pThis->papCerts[0]));
198 if (pv)
199 {
200 pThis->papCerts = (PRTCRSTOREINMEMCERT *)pv;
201 for (uint32_t i = pThis->cCertsAlloc; i < cMin; i++)
202 pThis->papCerts[i] = NULL;
203 pThis->cCertsAlloc = cMin;
204 return VINF_SUCCESS;
205 }
206 return VERR_NO_MEMORY;
207}
208
209
210
211/** @interface_method_impl{RTCRSTOREPROVIDER,pfnDestroyStore} */
212static DECLCALLBACK(void) rtCrStoreInMem_DestroyStore(void *pvProvider)
213{
214 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
215
216 while (pThis->cCerts > 0)
217 {
218 uint32_t i = --pThis->cCerts;
219 PRTCRSTOREINMEMCERT pEntry = pThis->papCerts[i];
220 pThis->papCerts[i] = NULL;
221 AssertPtr(pEntry);
222
223 pEntry->pStore = NULL;
224 RTCrCertCtxRelease(&pEntry->Core.Public);
225 }
226
227 RTMemFree(pThis->papCerts);
228 pThis->papCerts = NULL;
229
230 if (pThis->hParentStore != NIL_RTCRSTORE)
231 {
232 RTCrStoreRelease(pThis->hParentStore);
233 pThis->hParentStore = NIL_RTCRSTORE;
234 }
235
236 RTMemFree(pThis);
237}
238
239
240/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertCtxQueryPrivateKey} */
241static DECLCALLBACK(int) rtCrStoreInMem_CertCtxQueryPrivateKey(void *pvProvider, PRTCRCERTCTXINT pCertCtx,
242 uint8_t *pbKey, size_t cbKey, size_t *pcbKeyRet)
243{
244 RT_NOREF_PV(pvProvider); RT_NOREF_PV(pCertCtx); RT_NOREF_PV(pbKey); RT_NOREF_PV(cbKey); RT_NOREF_PV(pcbKeyRet);
245 //PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
246 return VERR_NOT_FOUND;
247}
248
249
250/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertFindAll} */
251static DECLCALLBACK(int) rtCrStoreInMem_CertFindAll(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
252{
253 pSearch->auOpaque[0] = ~(uintptr_t)pvProvider;
254 pSearch->auOpaque[1] = 0;
255 pSearch->auOpaque[2] = ~(uintptr_t)0; /* For the front-end API. */
256 pSearch->auOpaque[3] = ~(uintptr_t)0; /* For the front-end API. */
257 return VINF_SUCCESS;
258}
259
260
261/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchNext} */
262static DECLCALLBACK(PCRTCRCERTCTX) rtCrStoreInMem_CertSearchNext(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
263{
264 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
265 if (pSearch->auOpaque[0] == ~(uintptr_t)pvProvider)
266 {
267 uintptr_t i = pSearch->auOpaque[1];
268 if (i < pThis->cCerts)
269 {
270 pSearch->auOpaque[1] = i + 1;
271 PRTCRCERTCTXINT pCertCtx = &pThis->papCerts[i]->Core;
272 ASMAtomicIncU32(&pCertCtx->cRefs);
273 return &pCertCtx->Public;
274 }
275
276 /* Do we have a parent store to search? */
277 if (pThis->hParentStore == NIL_RTCRSTORE)
278 return NULL; /* no */
279 if ( !pThis->pParentProvider->pfnCertFindAll
280 || !pThis->pParentProvider->pfnCertSearchNext)
281 return NULL;
282
283 RTCRSTORECERTSEARCH const SavedSearch = *pSearch;
284 int rc = pThis->pParentProvider->pfnCertFindAll(pThis->pvParentProvider, pSearch);
285 AssertRCReturnStmt(rc, *pSearch = SavedSearch, NULL);
286
287 /* Restore the store.cpp specifics: */
288 AssertCompile(RT_ELEMENTS(SavedSearch.auOpaque) == 4);
289 pSearch->auOpaque[2] = SavedSearch.auOpaque[2];
290 pSearch->auOpaque[3] = SavedSearch.auOpaque[3];
291 }
292
293 AssertReturn(pThis->pParentProvider, NULL);
294 AssertReturn(pThis->pParentProvider->pfnCertSearchNext, NULL);
295 return pThis->pParentProvider->pfnCertSearchNext(pThis->pvParentProvider, pSearch);
296}
297
298
299/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchDestroy} */
300static DECLCALLBACK(void) rtCrStoreInMem_CertSearchDestroy(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
301{
302 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
303 if (pSearch->auOpaque[0] == ~(uintptr_t)pvProvider)
304 {
305 pSearch->auOpaque[0] = 0;
306 pSearch->auOpaque[1] = 0;
307 pSearch->auOpaque[2] = 0;
308 pSearch->auOpaque[3] = 0;
309 }
310 else
311 {
312 AssertReturnVoid(pThis->pParentProvider);
313 AssertReturnVoid(pThis->pParentProvider->pfnCertSearchDestroy);
314 pThis->pParentProvider->pfnCertSearchDestroy(pThis->pvParentProvider, pSearch);
315 }
316}
317
318
319/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchDestroy} */
320static DECLCALLBACK(int) rtCrStoreInMem_CertAddEncoded(void *pvProvider, uint32_t fFlags,
321 uint8_t const *pbEncoded, uint32_t cbEncoded, PRTERRINFO pErrInfo)
322{
323 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
324 int rc;
325
326 AssertMsgReturn( (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
327 || (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_TAF_DER
328 , ("Only X.509 and TAF DER are supported: %#x\n", fFlags), VERR_INVALID_FLAGS);
329
330 /*
331 * Check for duplicates if specified.
332 */
333 if (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND)
334 {
335 uint32_t iCert = pThis->cCerts;
336 while (iCert-- > 0)
337 {
338 PRTCRSTOREINMEMCERT pCert = pThis->papCerts[iCert];
339 if ( pCert->Core.Public.cbEncoded == cbEncoded
340 && pCert->Core.Public.fFlags == (fFlags & RTCRCERTCTX_F_ENC_MASK)
341 && memcmp(pCert->Core.Public.pabEncoded, pbEncoded, cbEncoded) == 0)
342 return VWRN_ALREADY_EXISTS;
343 }
344 }
345
346 /*
347 * Add it.
348 */
349 if (pThis->cCerts + 1 <= pThis->cCertsAlloc)
350 { /* likely */ }
351 else
352 {
353 rc = rtCrStoreInMemGrow(pThis, pThis->cCerts + 1);
354 if (RT_FAILURE(rc))
355 return rc;
356 }
357
358 rc = rtCrStoreInMemCreateCertEntry(pThis, fFlags & RTCRCERTCTX_F_ENC_MASK, pbEncoded, cbEncoded,
359 pErrInfo, &pThis->papCerts[pThis->cCerts]);
360 if (RT_SUCCESS(rc))
361 {
362 pThis->cCerts++;
363 return VINF_SUCCESS;
364 }
365 return rc;
366}
367
368
369/**
370 * In-memory store provider.
371 */
372static RTCRSTOREPROVIDER const g_rtCrStoreInMemProvider =
373{
374 "in-memory",
375 rtCrStoreInMem_DestroyStore,
376 rtCrStoreInMem_CertCtxQueryPrivateKey,
377 rtCrStoreInMem_CertFindAll,
378 rtCrStoreInMem_CertSearchNext,
379 rtCrStoreInMem_CertSearchDestroy,
380 rtCrStoreInMem_CertAddEncoded,
381 NULL,
382 42
383};
384
385
386/**
387 * Common worker for RTCrStoreCreateInMem and future constructors...
388 *
389 * @returns IPRT status code.
390 * @param ppStore Where to return the store instance.
391 * @param hParentStore Optional parent store. Consums reference on
392 * success.
393 */
394static int rtCrStoreInMemCreateInternal(PRTCRSTOREINMEM *ppStore, RTCRSTORE hParentStore)
395{
396 PRTCRSTOREINMEM pStore = (PRTCRSTOREINMEM)RTMemAlloc(sizeof(*pStore));
397 if (pStore)
398 {
399 pStore->cCerts = 0;
400 pStore->cCertsAlloc = 0;
401 pStore->papCerts = NULL;
402 pStore->hParentStore = hParentStore;
403 pStore->pParentProvider = NULL;
404 pStore->pvParentProvider = NULL;
405 *ppStore = pStore;
406 if (hParentStore == NIL_RTCRSTORE)
407 return VINF_SUCCESS;
408 if (~(uintptr_t)hParentStore != ~(uintptr_t)pStore)
409 {
410 pStore->pParentProvider = rtCrStoreGetProvider(hParentStore, &pStore->pvParentProvider);
411 if (pStore->pParentProvider)
412 return VINF_SUCCESS;
413 AssertFailed();
414 }
415 RTMemFree(pStore);
416 }
417 *ppStore = NULL; /* shut up gcc-maybe-pita warning. */
418 return VERR_NO_MEMORY;
419}
420
421
422RTDECL(int) RTCrStoreCreateInMemEx(PRTCRSTORE phStore, uint32_t cSizeHint, RTCRSTORE hParentStore)
423{
424 if (hParentStore != NIL_RTCRSTORE)
425 {
426 uint32_t cRefs = RTCrStoreRetain(hParentStore);
427 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
428 }
429
430 PRTCRSTOREINMEM pStore;
431 int rc = rtCrStoreInMemCreateInternal(&pStore, hParentStore);
432 if (RT_SUCCESS(rc))
433 {
434 if (cSizeHint)
435 rc = rtCrStoreInMemGrow(pStore, RT_MIN(cSizeHint, 512));
436 if (RT_SUCCESS(rc))
437 {
438 rc = rtCrStoreCreate(&g_rtCrStoreInMemProvider, pStore, phStore);
439 if (RT_SUCCESS(rc))
440 return VINF_SUCCESS;
441 }
442 RTMemFree(pStore);
443 }
444
445 RTCrStoreRelease(hParentStore);
446 return rc;
447}
448RT_EXPORT_SYMBOL(RTCrStoreCreateInMemEx);
449
450
451RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint)
452{
453 return RTCrStoreCreateInMemEx(phStore, cSizeHint, NIL_RTCRSTORE);
454}
455RT_EXPORT_SYMBOL(RTCrStoreCreateInMem);
456
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