VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use