VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/x509-certpaths.cpp@ 67092

Last change on this file since 67092 was 64883, checked in by vboxsync, 8 years ago

IPRT/ASN.1: Refactored array handling (SET OF, SEQUENCE OF) to use a pointer array instead of an object instance array. The old approach would move objects around in memory after they'd be initialized/decoded, making certain core optimziations involving pointers to object members impossible, as well as causing potentially causing trouble when modifying structures that takes down pointers after decoding. Fixed validation bug in rtCrX509Name_CheckSanityExtra where it didn't check that the RDNs had subitems but instead checked the parent twice (slight risk).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 106.3 KB
Line 
1/* $Id: x509-certpaths.cpp 64883 2016-12-15 15:26:20Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - X.509, Simple Certificate Path Builder & Validator.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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#define LOG_GROUP RTLOGGROUP_CRYPTO
32#include "internal/iprt.h"
33#include <iprt/crypto/x509.h>
34
35#include <iprt/asm.h>
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include <iprt/list.h>
41#include <iprt/log.h>
42#include <iprt/time.h>
43#include <iprt/crypto/pkcs7.h> /* PCRTCRPKCS7SETOFCERTS */
44#include <iprt/crypto/store.h>
45
46#include "x509-internal.h"
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52/**
53 * X.509 certificate path node.
54 */
55typedef struct RTCRX509CERTPATHNODE
56{
57 /** Sibling list entry. */
58 RTLISTNODE SiblingEntry;
59 /** List of children or leaf list entry. */
60 RTLISTANCHOR ChildListOrLeafEntry;
61 /** Pointer to the parent node. NULL for root. */
62 struct RTCRX509CERTPATHNODE *pParent;
63
64 /** The distance between this node and the target. */
65 uint32_t uDepth : 8;
66 /** Indicates the source of this certificate. */
67 uint32_t uSrc : 3;
68 /** Set if this is a leaf node. */
69 uint32_t fLeaf : 1;
70 /** Makes sure it's a 32-bit bitfield. */
71 uint32_t uReserved : 20;
72
73 /** Leaf only: The result of the last path vertification. */
74 int rcVerify;
75
76 /** Pointer to the certificate. This can be NULL only for trust anchors. */
77 PCRTCRX509CERTIFICATE pCert;
78
79 /** If the certificate or trust anchor was obtained from a store, this is the
80 * associated certificate context (referenced of course). This is used to
81 * access the trust anchor information, if present.
82 *
83 * (If this is NULL it's from a certificate array or some such given directly to
84 * the path building code. It's assumed the caller doesn't free these until the
85 * path validation/whatever is done with and the paths destroyed.) */
86 PCRTCRCERTCTX pCertCtx;
87} RTCRX509CERTPATHNODE;
88/** Pointer to a X.509 path node. */
89typedef RTCRX509CERTPATHNODE *PRTCRX509CERTPATHNODE;
90
91/** @name RTCRX509CERTPATHNODE::uSrc values.
92 * The trusted and untrusted sources ordered in priority order, where higher
93 * number means high priority in case of duplicates.
94 * @{ */
95#define RTCRX509CERTPATHNODE_SRC_NONE 0
96#define RTCRX509CERTPATHNODE_SRC_TARGET 1
97#define RTCRX509CERTPATHNODE_SRC_UNTRUSTED_SET 2
98#define RTCRX509CERTPATHNODE_SRC_UNTRUSTED_ARRAY 3
99#define RTCRX509CERTPATHNODE_SRC_UNTRUSTED_STORE 4
100#define RTCRX509CERTPATHNODE_SRC_TRUSTED_STORE 5
101#define RTCRX509CERTPATHNODE_SRC_TRUSTED_CERT 6
102#define RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(uSrc) ((uSrc) >= RTCRX509CERTPATHNODE_SRC_TRUSTED_STORE)
103/** @} */
104
105
106/**
107 * Policy tree node.
108 */
109typedef struct RTCRX509CERTPATHSPOLICYNODE
110{
111 /** Sibling list entry. */
112 RTLISTNODE SiblingEntry;
113 /** Tree depth list entry. */
114 RTLISTNODE DepthEntry;
115 /** List of children or leaf list entry. */
116 RTLISTANCHOR ChildList;
117 /** Pointer to the parent. */
118 struct RTCRX509CERTPATHSPOLICYNODE *pParent;
119
120 /** The policy object ID. */
121 PCRTASN1OBJID pValidPolicy;
122
123 /** Optional sequence of policy qualifiers. */
124 PCRTCRX509POLICYQUALIFIERINFOS pPolicyQualifiers;
125
126 /** The first policy ID in the exepcted policy set. */
127 PCRTASN1OBJID pExpectedPolicyFirst;
128 /** Set if we've already mapped pExpectedPolicyFirst. */
129 bool fAlreadyMapped;
130 /** Number of additional items in the expected policy set. */
131 uint32_t cMoreExpectedPolicySet;
132 /** Additional items in the expected policy set. */
133 PCRTASN1OBJID *papMoreExpectedPolicySet;
134} RTCRX509CERTPATHSPOLICYNODE;
135/** Pointer to a policy tree node. */
136typedef RTCRX509CERTPATHSPOLICYNODE *PRTCRX509CERTPATHSPOLICYNODE;
137
138
139/**
140 * Path builder and validator instance.
141 *
142 * The path builder creates a tree of certificates by forward searching from the
143 * end-entity towards a trusted source. The leaf nodes are inserted into list
144 * ordered by the source of the leaf certificate and the path length (i.e. tree
145 * depth).
146 *
147 * The path validator works the tree from the leaf end and validates each
148 * potential path found by the builder. It is generally happy with one working
149 * path, but may be told to verify all of them.
150 */
151typedef struct RTCRX509CERTPATHSINT
152{
153 /** Magic number. */
154 uint32_t u32Magic;
155 /** Reference counter. */
156 uint32_t volatile cRefs;
157
158 /** @name Input
159 * @{ */
160 /** The target certificate (end entity) to build a trusted path for. */
161 PCRTCRX509CERTIFICATE pTarget;
162
163 /** Lone trusted certificate. */
164 PCRTCRX509CERTIFICATE pTrustedCert;
165 /** Store of trusted certificates. */
166 RTCRSTORE hTrustedStore;
167
168 /** Store of untrusted certificates. */
169 RTCRSTORE hUntrustedStore;
170 /** Array of untrusted certificates, typically from the protocol. */
171 PCRTCRX509CERTIFICATE paUntrustedCerts;
172 /** Number of entries in paUntrusted. */
173 uint32_t cUntrustedCerts;
174 /** Set of untrusted PKCS \#7 / CMS certificatess. */
175 PCRTCRPKCS7SETOFCERTS pUntrustedCertsSet;
176
177 /** UTC time we're going to validate the path at, requires
178 * RTCRX509CERTPATHSINT_F_VALID_TIME to be set. */
179 RTTIMESPEC ValidTime;
180 /** Number of policy OIDs in the user initial policy set, 0 means anyPolicy. */
181 uint32_t cInitialUserPolicySet;
182 /** The user initial policy set. As with all other user provided data, we
183 * assume it's immutable and remains valid for the usage period of the path
184 * builder & validator. */
185 PCRTASN1OBJID *papInitialUserPolicySet;
186 /** Number of certificates before the user wants an explicit policy result.
187 * Set to UINT32_MAX no explicit policy restriction required by the user. */
188 uint32_t cInitialExplicitPolicy;
189 /** Number of certificates before the user wants policy mapping to be
190 * inhibited. Set to UINT32_MAX if no initial policy mapping inhibition
191 * desired by the user. */
192 uint32_t cInitialPolicyMappingInhibit;
193 /** Number of certificates before the user wants the anyPolicy to be rejected.
194 * Set to UINT32_MAX no explicit policy restriction required by the user. */
195 uint32_t cInitialInhibitAnyPolicy;
196 /** Initial name restriction: Permitted subtrees. */
197 PCRTCRX509GENERALSUBTREES pInitialPermittedSubtrees;
198 /** Initial name restriction: Excluded subtrees. */
199 PCRTCRX509GENERALSUBTREES pInitialExcludedSubtrees;
200
201 /** Flags RTCRX509CERTPATHSINT_F_XXX. */
202 uint32_t fFlags;
203 /** @} */
204
205 /** Sticky status for remembering allocation errors and the like. */
206 int32_t rc;
207 /** Where to store extended error info (optional). */
208 PRTERRINFO pErrInfo;
209
210 /** @name Path Builder Output
211 * @{ */
212 /** Pointer to the root of the tree. This will always be non-NULL after path
213 * building and thus can be reliably used to tell if path building has taken
214 * place or not. */
215 PRTCRX509CERTPATHNODE pRoot;
216 /** List of working leaf tree nodes. */
217 RTLISTANCHOR LeafList;
218 /** The number of paths (leafs). */
219 uint32_t cPaths;
220 /** @} */
221
222 /** Path Validator State. */
223 struct
224 {
225 /** Number of nodes in the certificate path we're validating (aka 'n'). */
226 uint32_t cNodes;
227 /** The current node (0 being the trust anchor). */
228 uint32_t iNode;
229
230 /** The root node of the valid policy tree. */
231 PRTCRX509CERTPATHSPOLICYNODE pValidPolicyTree;
232 /** An array of length cNodes + 1 which tracks all nodes at the given (index)
233 * tree depth via the RTCRX509CERTPATHSPOLICYNODE::DepthEntry member. */
234 PRTLISTANCHOR paValidPolicyDepthLists;
235
236 /** Number of entries in paPermittedSubtrees (name constraints).
237 * If zero, no permitted name constrains currently in effect. */
238 uint32_t cPermittedSubtrees;
239 /** The allocated size of papExcludedSubtrees */
240 uint32_t cPermittedSubtreesAlloc;
241 /** Array of permitted subtrees we've collected so far (name constraints). */
242 PCRTCRX509GENERALSUBTREE *papPermittedSubtrees;
243 /** Set if we end up with an empty set after calculating a name constraints
244 * union. */
245 bool fNoPermittedSubtrees;
246
247 /** Number of entries in paExcludedSubtrees (name constraints).
248 * If zero, no excluded name constrains currently in effect. */
249 uint32_t cExcludedSubtrees;
250 /** Array of excluded subtrees we've collected so far (name constraints). */
251 PCRTCRX509GENERALSUBTREES *papExcludedSubtrees;
252
253 /** Number of non-self-issued certificates to be processed before a non-NULL
254 * paValidPolicyTree is required. */
255 uint32_t cExplicitPolicy;
256 /** Number of non-self-issued certificates to be processed we stop processing
257 * policy mapping extensions. */
258 uint32_t cInhibitPolicyMapping;
259 /** Number of non-self-issued certificates to be processed before a the
260 * anyPolicy is rejected. */
261 uint32_t cInhibitAnyPolicy;
262 /** Number of non-self-issued certificates we're allowed to process. */
263 uint32_t cMaxPathLength;
264
265 /** The working issuer name. */
266 PCRTCRX509NAME pWorkingIssuer;
267 /** The working public key algorithm ID. */
268 PCRTASN1OBJID pWorkingPublicKeyAlgorithm;
269 /** The working public key algorithm parameters. */
270 PCRTASN1DYNTYPE pWorkingPublicKeyParameters;
271 /** A bit string containing the public key. */
272 PCRTASN1BITSTRING pWorkingPublicKey;
273 } v;
274
275 /** An object identifier initialized to anyPolicy. */
276 RTASN1OBJID AnyPolicyObjId;
277
278 /** Temporary scratch space. */
279 char szTmp[1024];
280} RTCRX509CERTPATHSINT;
281typedef RTCRX509CERTPATHSINT *PRTCRX509CERTPATHSINT;
282
283/** Magic value for RTCRX509CERTPATHSINT::u32Magic (Bruce Schneier). */
284#define RTCRX509CERTPATHSINT_MAGIC UINT32_C(0x19630115)
285
286/** @name RTCRX509CERTPATHSINT_F_XXX - Certificate path build flags.
287 * @{ */
288#define RTCRX509CERTPATHSINT_F_VALID_TIME RT_BIT_32(0)
289#define RTCRX509CERTPATHSINT_F_ELIMINATE_UNTRUSTED_PATHS RT_BIT_32(1)
290#define RTCRX509CERTPATHSINT_F_VALID_MASK UINT32_C(0x00000003)
291/** @} */
292
293
294/*********************************************************************************************************************************
295* Internal Functions *
296*********************************************************************************************************************************/
297static void rtCrX509CertPathsDestroyTree(PRTCRX509CERTPATHSINT pThis);
298static void rtCrX509CpvCleanup(PRTCRX509CERTPATHSINT pThis);
299
300
301/** @name Path Builder and Validator Config APIs
302 * @{
303 */
304
305RTDECL(int) RTCrX509CertPathsCreate(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget)
306{
307 AssertPtrReturn(phCertPaths, VERR_INVALID_POINTER);
308
309 PRTCRX509CERTPATHSINT pThis = (PRTCRX509CERTPATHSINT)RTMemAllocZ(sizeof(*pThis));
310 if (pThis)
311 {
312 int rc = RTAsn1ObjId_InitFromString(&pThis->AnyPolicyObjId, RTCRX509_ID_CE_CP_ANY_POLICY_OID, &g_RTAsn1DefaultAllocator);
313 if (RT_SUCCESS(rc))
314 {
315 pThis->u32Magic = RTCRX509CERTPATHSINT_MAGIC;
316 pThis->cRefs = 1;
317 pThis->pTarget = pTarget;
318 pThis->hTrustedStore = NIL_RTCRSTORE;
319 pThis->hUntrustedStore = NIL_RTCRSTORE;
320 pThis->cInitialExplicitPolicy = UINT32_MAX;
321 pThis->cInitialPolicyMappingInhibit = UINT32_MAX;
322 pThis->cInitialInhibitAnyPolicy = UINT32_MAX;
323 pThis->rc = VINF_SUCCESS;
324 RTListInit(&pThis->LeafList);
325 *phCertPaths = pThis;
326 return VINF_SUCCESS;
327 }
328 return rc;
329 }
330 return VERR_NO_MEMORY;
331}
332
333
334RTDECL(uint32_t) RTCrX509CertPathsRetain(RTCRX509CERTPATHS hCertPaths)
335{
336 PRTCRX509CERTPATHSINT pThis = hCertPaths;
337 AssertPtrReturn(pThis, UINT32_MAX);
338
339 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
340 Assert(cRefs > 0 && cRefs < 64);
341 return cRefs;
342}
343
344
345RTDECL(uint32_t) RTCrX509CertPathsRelease(RTCRX509CERTPATHS hCertPaths)
346{
347 uint32_t cRefs;
348 if (hCertPaths != NIL_RTCRX509CERTPATHS)
349 {
350 PRTCRX509CERTPATHSINT pThis = hCertPaths;
351 AssertPtrReturn(pThis, UINT32_MAX);
352 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, UINT32_MAX);
353
354 cRefs = ASMAtomicDecU32(&pThis->cRefs);
355 Assert(cRefs < 64);
356 if (!cRefs)
357 {
358 /*
359 * No more references, destroy the whole thing.
360 */
361 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRX509CERTPATHSINT_MAGIC);
362
363 /* config */
364 pThis->pTarget = NULL; /* Referencing user memory. */
365 pThis->pTrustedCert = NULL; /* Referencing user memory. */
366 RTCrStoreRelease(pThis->hTrustedStore);
367 pThis->hTrustedStore = NIL_RTCRSTORE;
368 RTCrStoreRelease(pThis->hUntrustedStore);
369 pThis->hUntrustedStore = NIL_RTCRSTORE;
370 pThis->paUntrustedCerts = NULL; /* Referencing user memory. */
371 pThis->pUntrustedCertsSet = NULL; /* Referencing user memory. */
372 pThis->papInitialUserPolicySet = NULL; /* Referencing user memory. */
373 pThis->pInitialPermittedSubtrees = NULL; /* Referencing user memory. */
374 pThis->pInitialExcludedSubtrees = NULL; /* Referencing user memory. */
375
376 /* builder */
377 rtCrX509CertPathsDestroyTree(pThis);
378
379 /* validator */
380 rtCrX509CpvCleanup(pThis);
381
382 /* misc */
383 RTAsn1VtDelete(&pThis->AnyPolicyObjId.Asn1Core);
384
385 /* Finally, the instance itself. */
386 RTMemFree(pThis);
387 }
388 }
389 else
390 cRefs = 0;
391 return cRefs;
392}
393
394
395
396RTDECL(int) RTCrX509CertPathsSetTrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hTrustedStore)
397{
398 PRTCRX509CERTPATHSINT pThis = hCertPaths;
399 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
400 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
401 AssertReturn(pThis->pRoot == NULL, VERR_WRONG_ORDER);
402
403 if (pThis->hTrustedStore != NIL_RTCRSTORE)
404 {
405 RTCrStoreRelease(pThis->hTrustedStore);
406 pThis->hTrustedStore = NIL_RTCRSTORE;
407 }
408 if (hTrustedStore != NIL_RTCRSTORE)
409 {
410 AssertReturn(RTCrStoreRetain(hTrustedStore) != UINT32_MAX, VERR_INVALID_HANDLE);
411 pThis->hTrustedStore = hTrustedStore;
412 }
413 return VINF_SUCCESS;
414}
415
416
417RTDECL(int) RTCrX509CertPathsSetUntrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hUntrustedStore)
418{
419 PRTCRX509CERTPATHSINT pThis = hCertPaths;
420 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
421 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
422 AssertReturn(pThis->pRoot == NULL, VERR_WRONG_ORDER);
423
424 if (pThis->hUntrustedStore != NIL_RTCRSTORE)
425 {
426 RTCrStoreRelease(pThis->hUntrustedStore);
427 pThis->hUntrustedStore = NIL_RTCRSTORE;
428 }
429 if (hUntrustedStore != NIL_RTCRSTORE)
430 {
431 AssertReturn(RTCrStoreRetain(hUntrustedStore) != UINT32_MAX, VERR_INVALID_HANDLE);
432 pThis->hUntrustedStore = hUntrustedStore;
433 }
434 return VINF_SUCCESS;
435}
436
437
438RTDECL(int) RTCrX509CertPathsSetUntrustedArray(RTCRX509CERTPATHS hCertPaths, PCRTCRX509CERTIFICATE paCerts, uint32_t cCerts)
439{
440 PRTCRX509CERTPATHSINT pThis = hCertPaths;
441 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
442 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
443
444 pThis->paUntrustedCerts = paCerts;
445 pThis->cUntrustedCerts = cCerts;
446 return VINF_SUCCESS;
447}
448
449
450RTDECL(int) RTCrX509CertPathsSetUntrustedSet(RTCRX509CERTPATHS hCertPaths, PCRTCRPKCS7SETOFCERTS pSetOfCerts)
451{
452 PRTCRX509CERTPATHSINT pThis = hCertPaths;
453 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
454 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
455
456 pThis->pUntrustedCertsSet = pSetOfCerts;
457 return VINF_SUCCESS;
458}
459
460
461RTDECL(int) RTCrX509CertPathsSetValidTime(RTCRX509CERTPATHS hCertPaths, PCRTTIME pTime)
462{
463 PRTCRX509CERTPATHSINT pThis = hCertPaths;
464 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
465 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
466
467 /* Allow this after building paths, as it's only used during verification. */
468
469 if (pTime)
470 {
471 if (RTTimeImplode(&pThis->ValidTime, pTime))
472 return VERR_INVALID_PARAMETER;
473 pThis->fFlags |= RTCRX509CERTPATHSINT_F_VALID_TIME;
474 }
475 else
476 pThis->fFlags &= ~RTCRX509CERTPATHSINT_F_VALID_TIME;
477 return VINF_SUCCESS;
478}
479
480
481RTDECL(int) RTCrX509CertPathsSetValidTimeSpec(RTCRX509CERTPATHS hCertPaths, PCRTTIMESPEC pTimeSpec)
482{
483 PRTCRX509CERTPATHSINT pThis = hCertPaths;
484 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
485 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
486
487 /* Allow this after building paths, as it's only used during verification. */
488
489 if (pTimeSpec)
490 {
491 pThis->ValidTime = *pTimeSpec;
492 pThis->fFlags |= RTCRX509CERTPATHSINT_F_VALID_TIME;
493 }
494 else
495 pThis->fFlags &= ~RTCRX509CERTPATHSINT_F_VALID_TIME;
496 return VINF_SUCCESS;
497}
498
499
500RTDECL(int) RTCrX509CertPathsCreateEx(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget, RTCRSTORE hTrustedStore,
501 RTCRSTORE hUntrustedStore, PCRTCRX509CERTIFICATE paUntrustedCerts, uint32_t cUntrustedCerts,
502 PCRTTIMESPEC pValidTime)
503{
504 int rc = RTCrX509CertPathsCreate(phCertPaths, pTarget);
505 if (RT_SUCCESS(rc))
506 {
507 PRTCRX509CERTPATHSINT pThis = *phCertPaths;
508
509 rc = RTCrX509CertPathsSetTrustedStore(pThis, hTrustedStore);
510 if (RT_SUCCESS(rc))
511 {
512 rc = RTCrX509CertPathsSetUntrustedStore(pThis, hUntrustedStore);
513 if (RT_SUCCESS(rc))
514 {
515 rc = RTCrX509CertPathsSetUntrustedArray(pThis, paUntrustedCerts, cUntrustedCerts);
516 if (RT_SUCCESS(rc))
517 {
518 rc = RTCrX509CertPathsSetValidTimeSpec(pThis, pValidTime);
519 if (RT_SUCCESS(rc))
520 {
521 return VINF_SUCCESS;
522 }
523 }
524 RTCrStoreRelease(pThis->hUntrustedStore);
525 }
526 RTCrStoreRelease(pThis->hTrustedStore);
527 }
528 RTMemFree(pThis);
529 *phCertPaths = NIL_RTCRX509CERTPATHS;
530 }
531 return rc;
532}
533
534/** @} */
535
536
537
538/** @name Path Builder and Validator Common Utility Functions.
539 * @{
540 */
541
542/**
543 * Checks if the certificate is self-issued.
544 *
545 * @returns true / false.
546 * @param pNode The path node to check..
547 */
548static bool rtCrX509CertPathsIsSelfIssued(PRTCRX509CERTPATHNODE pNode)
549{
550 return pNode->pCert
551 && RTCrX509Name_MatchByRfc5280(&pNode->pCert->TbsCertificate.Subject, &pNode->pCert->TbsCertificate.Issuer);
552}
553
554/** @} */
555
556
557
558/** @name Path Builder Functions.
559 * @{
560 */
561
562/**
563 *
564 * @returns
565 * @param pThis .
566 */
567static PRTCRX509CERTPATHNODE rtCrX509CertPathsNewNode(PRTCRX509CERTPATHSINT pThis)
568{
569 PRTCRX509CERTPATHNODE pNode = (PRTCRX509CERTPATHNODE)RTMemAllocZ(sizeof(*pNode));
570 if (RT_LIKELY(pNode))
571 {
572 RTListInit(&pNode->SiblingEntry);
573 RTListInit(&pNode->ChildListOrLeafEntry);
574 pNode->rcVerify = VERR_CR_X509_NOT_VERIFIED;
575
576 return pNode;
577 }
578
579 pThis->rc = RTErrInfoSet(pThis->pErrInfo, VERR_NO_MEMORY, "No memory for path node");
580 return NULL;
581}
582
583
584static void rtCrX509CertPathsDestroyNode(PRTCRX509CERTPATHNODE pNode)
585{
586 if (pNode->pCertCtx)
587 {
588 RTCrCertCtxRelease(pNode->pCertCtx);
589 pNode->pCertCtx = NULL;
590 }
591 RT_ZERO(*pNode);
592 RTMemFree(pNode);
593}
594
595
596static void rtCrX509CertPathsAddIssuer(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pParent,
597 PCRTCRX509CERTIFICATE pCert, PCRTCRCERTCTX pCertCtx, uint8_t uSrc)
598{
599 /*
600 * Check if we've seen this certificate already in the current path or
601 * among the already gathered issuers.
602 */
603 if (pCert)
604 {
605 /* No duplicate certificates in the path. */
606 PRTCRX509CERTPATHNODE pTmpNode = pParent;
607 while (pTmpNode)
608 {
609 Assert(pTmpNode->pCert);
610 if ( pTmpNode->pCert == pCert
611 || RTCrX509Certificate_Compare(pTmpNode->pCert, pCert) == 0)
612 return;
613 pTmpNode = pTmpNode->pParent;
614 }
615
616 /* No duplicate tree branches. */
617 RTListForEach(&pParent->ChildListOrLeafEntry, pTmpNode, RTCRX509CERTPATHNODE, SiblingEntry)
618 {
619 if (RTCrX509Certificate_Compare(pTmpNode->pCert, pCert) == 0)
620 return;
621 }
622 }
623 else
624 Assert(pCertCtx);
625
626 /*
627 * Reference the context core before making the allocation.
628 */
629 if (pCertCtx)
630 AssertReturnVoidStmt(RTCrCertCtxRetain(pCertCtx) != UINT32_MAX,
631 pThis->rc = RTErrInfoSetF(pThis->pErrInfo, VERR_CR_X509_CPB_BAD_CERT_CTX,
632 "Bad pCertCtx=%p", pCertCtx));
633
634 /*
635 * We haven't see it, append it as a child.
636 */
637 PRTCRX509CERTPATHNODE pNew = rtCrX509CertPathsNewNode(pThis);
638 if (pNew)
639 {
640 pNew->pParent = pParent;
641 pNew->pCert = pCert;
642 pNew->pCertCtx = pCertCtx;
643 pNew->uSrc = uSrc;
644 pNew->uDepth = pParent->uDepth + 1;
645 RTListAppend(&pParent->ChildListOrLeafEntry, &pNew->SiblingEntry);
646 }
647 else
648 RTCrCertCtxRelease(pCertCtx);
649}
650
651
652static void rtCrX509CertPathsGetIssuersFromStore(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode,
653 PCRTCRX509NAME pIssuer, RTCRSTORE hStore, uint8_t uSrc)
654{
655 RTCRSTORECERTSEARCH Search;
656 int rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(hStore, pIssuer, &Search);
657 if (RT_SUCCESS(rc))
658 {
659 PCRTCRCERTCTX pCertCtx;
660 while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
661 {
662 if ( pCertCtx->pCert
663 || ( RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(uSrc)
664 && pCertCtx->pTaInfo) )
665 rtCrX509CertPathsAddIssuer(pThis, pNode, pCertCtx->pCert, pCertCtx, uSrc);
666 RTCrCertCtxRelease(pCertCtx);
667 }
668 RTCrStoreCertSearchDestroy(hStore, &Search);
669 }
670}
671
672
673static void rtCrX509CertPathsGetIssuers(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
674{
675 Assert(RTListIsEmpty(&pNode->ChildListOrLeafEntry));
676 Assert(!pNode->fLeaf);
677 Assert(pNode->pCert);
678
679 /*
680 * Don't recurse infintely.
681 */
682 if (RT_UNLIKELY(pNode->uDepth >= 50))
683 return;
684
685 PCRTCRX509NAME const pIssuer = &pNode->pCert->TbsCertificate.Issuer;
686
687 /*
688 * Trusted certificate.
689 */
690 if ( pThis->pTrustedCert
691 && RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(pThis->pTrustedCert, pIssuer))
692 rtCrX509CertPathsAddIssuer(pThis, pNode, pThis->pTrustedCert, NULL, RTCRX509CERTPATHNODE_SRC_TRUSTED_CERT);
693
694 /*
695 * Trusted certificate store.
696 */
697 if (pThis->hTrustedStore != NIL_RTCRSTORE)
698 rtCrX509CertPathsGetIssuersFromStore(pThis, pNode, pIssuer, pThis->hTrustedStore,
699 RTCRX509CERTPATHNODE_SRC_TRUSTED_STORE);
700
701 /*
702 * Untrusted store.
703 */
704 if (pThis->hUntrustedStore != NIL_RTCRSTORE)
705 rtCrX509CertPathsGetIssuersFromStore(pThis, pNode, pIssuer, pThis->hTrustedStore,
706 RTCRX509CERTPATHNODE_SRC_UNTRUSTED_STORE);
707
708 /*
709 * Untrusted array.
710 */
711 if (pThis->paUntrustedCerts)
712 for (uint32_t i = 0; i < pThis->cUntrustedCerts; i++)
713 if (RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(&pThis->paUntrustedCerts[i], pIssuer))
714 rtCrX509CertPathsAddIssuer(pThis, pNode, &pThis->paUntrustedCerts[i], NULL,
715 RTCRX509CERTPATHNODE_SRC_UNTRUSTED_ARRAY);
716
717 /** @todo Rainy day: Should abstract the untrusted array and set so we don't get
718 * unnecessary PKCS7/CMS header dependencies. */
719
720 /*
721 * Untrusted set.
722 */
723 if (pThis->pUntrustedCertsSet)
724 {
725 uint32_t const cCerts = pThis->pUntrustedCertsSet->cItems;
726 PRTCRPKCS7CERT const *papCerts = pThis->pUntrustedCertsSet->papItems;
727 for (uint32_t i = 0; i < cCerts; i++)
728 {
729 PCRTCRPKCS7CERT pCert = papCerts[i];
730 if ( pCert->enmChoice == RTCRPKCS7CERTCHOICE_X509
731 && RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(pCert->u.pX509Cert, pIssuer))
732 rtCrX509CertPathsAddIssuer(pThis, pNode, pCert->u.pX509Cert, NULL, RTCRX509CERTPATHNODE_SRC_UNTRUSTED_SET);
733 }
734 }
735}
736
737
738static PRTCRX509CERTPATHNODE rtCrX509CertPathsGetNextRightUp(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
739{
740 for (;;)
741 {
742 /* The root node has no siblings. */
743 PRTCRX509CERTPATHNODE pParent = pNode->pParent;
744 if (!pNode->pParent)
745 return NULL;
746
747 /* Try go to the right. */
748 PRTCRX509CERTPATHNODE pNext = RTListGetNext(&pParent->ChildListOrLeafEntry, pNode, RTCRX509CERTPATHNODE, SiblingEntry);
749 if (pNext)
750 return pNext;
751
752 /* Up. */
753 pNode = pParent;
754 }
755
756 RT_NOREF_PV(pThis);
757}
758
759
760static PRTCRX509CERTPATHNODE rtCrX509CertPathsEliminatePath(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
761{
762 for (;;)
763 {
764 Assert(RTListIsEmpty(&pNode->ChildListOrLeafEntry));
765
766 /* Don't remove the root node. */
767 PRTCRX509CERTPATHNODE pParent = pNode->pParent;
768 if (!pParent)
769 return NULL;
770
771 /* Before removing and deleting the node check if there is sibling
772 right to it that we should continue processing from. */
773 PRTCRX509CERTPATHNODE pNext = RTListGetNext(&pParent->ChildListOrLeafEntry, pNode, RTCRX509CERTPATHNODE, SiblingEntry);
774 RTListNodeRemove(&pNode->SiblingEntry);
775 rtCrX509CertPathsDestroyNode(pNode);
776
777 if (pNext)
778 return pNext;
779
780 /* If the parent node cannot be removed, do a normal get-next-rigth-up
781 to find the continuation point for the tree loop. */
782 if (!RTListIsEmpty(&pParent->ChildListOrLeafEntry))
783 return rtCrX509CertPathsGetNextRightUp(pThis, pParent);
784
785 pNode = pParent;
786 }
787}
788
789
790/**
791 * Destroys the whole path tree.
792 *
793 * @param pThis The path builder and verifier instance.
794 */
795static void rtCrX509CertPathsDestroyTree(PRTCRX509CERTPATHSINT pThis)
796{
797 PRTCRX509CERTPATHNODE pNode, pNextLeaf;
798 RTListForEachSafe(&pThis->LeafList, pNode, pNextLeaf, RTCRX509CERTPATHNODE, ChildListOrLeafEntry)
799 {
800 RTListNodeRemove(&pNode->ChildListOrLeafEntry);
801 RTListInit(&pNode->ChildListOrLeafEntry);
802
803 for (;;)
804 {
805 PRTCRX509CERTPATHNODE pParent = pNode->pParent;
806
807 RTListNodeRemove(&pNode->SiblingEntry);
808 rtCrX509CertPathsDestroyNode(pNode);
809
810 if (!pParent)
811 {
812 pThis->pRoot = NULL;
813 break;
814 }
815
816 if (!RTListIsEmpty(&pParent->ChildListOrLeafEntry))
817 break;
818
819 pNode = pParent;
820 }
821 }
822 Assert(!pThis->pRoot);
823}
824
825
826/**
827 * Adds a leaf node.
828 *
829 * This should normally be a trusted certificate, but the caller can also
830 * request the incomplete paths, in which case this will be an untrusted
831 * certificate.
832 *
833 * @returns Pointer to the next node in the tree to process.
834 * @param pThis The path builder instance.
835 * @param pNode The leaf node.
836 */
837static PRTCRX509CERTPATHNODE rtCrX509CertPathsAddLeaf(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
838{
839 pNode->fLeaf = true;
840
841 /*
842 * Priority insert by source and depth.
843 */
844 PRTCRX509CERTPATHNODE pCurLeaf;
845 RTListForEach(&pThis->LeafList, pCurLeaf, RTCRX509CERTPATHNODE, ChildListOrLeafEntry)
846 {
847 if ( pNode->uSrc > pCurLeaf->uSrc
848 || ( pNode->uSrc == pCurLeaf->uSrc
849 && pNode->uDepth < pCurLeaf->uDepth) )
850 {
851 RTListNodeInsertBefore(&pCurLeaf->ChildListOrLeafEntry, &pNode->ChildListOrLeafEntry);
852 pThis->cPaths++;
853 return rtCrX509CertPathsGetNextRightUp(pThis, pNode);
854 }
855 }
856
857 RTListAppend(&pThis->LeafList, &pNode->ChildListOrLeafEntry);
858 pThis->cPaths++;
859 return rtCrX509CertPathsGetNextRightUp(pThis, pNode);
860}
861
862
863
864RTDECL(int) RTCrX509CertPathsBuild(RTCRX509CERTPATHS hCertPaths, PRTERRINFO pErrInfo)
865{
866 /*
867 * Validate the input.
868 */
869 PRTCRX509CERTPATHSINT pThis = hCertPaths;
870 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
871 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
872 AssertReturn(!(pThis->fFlags & ~RTCRX509CERTPATHSINT_F_VALID_MASK), VERR_INVALID_PARAMETER);
873 AssertReturn( (pThis->paUntrustedCerts == NULL && pThis->cUntrustedCerts == 0)
874 || (pThis->paUntrustedCerts != NULL && pThis->cUntrustedCerts > 0),
875 VERR_INVALID_PARAMETER);
876 AssertReturn(RTListIsEmpty(&pThis->LeafList), VERR_INVALID_PARAMETER);
877 AssertReturn(pThis->pRoot == NULL, VERR_INVALID_PARAMETER);
878 AssertReturn(pThis->rc == VINF_SUCCESS, pThis->rc);
879 AssertPtrReturn(pThis->pTarget, VERR_INVALID_PARAMETER);
880 Assert(RT_SUCCESS(RTCrX509Certificate_CheckSanity(pThis->pTarget, 0, NULL, NULL)));
881
882 /*
883 * Set up the target.
884 */
885 PRTCRX509CERTPATHNODE pCur;
886 pThis->pRoot = pCur = rtCrX509CertPathsNewNode(pThis);
887 if (pThis->pRoot)
888 {
889 pCur->pCert = pThis->pTarget;
890 pCur->uDepth = 0;
891 pCur->uSrc = RTCRX509CERTPATHNODE_SRC_TARGET;
892
893 pThis->pErrInfo = pErrInfo;
894
895 /*
896 * The tree construction loop.
897 * Walks down, up, and right as the tree is constructed.
898 */
899 do
900 {
901 /*
902 * Check for the two leaf cases first.
903 */
904 if (RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(pCur->uSrc))
905 pCur = rtCrX509CertPathsAddLeaf(pThis, pCur);
906#if 0 /* This isn't right.*/
907 else if (rtCrX509CertPathsIsSelfIssued(pCur))
908 {
909 if (pThis->fFlags & RTCRX509CERTPATHSINT_F_ELIMINATE_UNTRUSTED_PATHS)
910 pCur = rtCrX509CertPathsEliminatePath(pThis, pCur);
911 else
912 pCur = rtCrX509CertPathsAddLeaf(pThis, pCur);
913 }
914#endif
915 /*
916 * Not a leaf, find all potential issuers and decend into these.
917 */
918 else
919 {
920 rtCrX509CertPathsGetIssuers(pThis, pCur);
921 if (RT_FAILURE(pThis->rc))
922 break;
923
924 if (!RTListIsEmpty(&pCur->ChildListOrLeafEntry))
925 pCur = RTListGetFirst(&pCur->ChildListOrLeafEntry, RTCRX509CERTPATHNODE, SiblingEntry);
926 else if (pThis->fFlags & RTCRX509CERTPATHSINT_F_ELIMINATE_UNTRUSTED_PATHS)
927 pCur = rtCrX509CertPathsEliminatePath(pThis, pCur);
928 else
929 pCur = rtCrX509CertPathsAddLeaf(pThis, pCur);
930 }
931 if (pCur)
932 Log2(("RTCrX509CertPathsBuild: pCur=%p fLeaf=%d pParent=%p pNext=%p pPrev=%p\n",
933 pCur, pCur->fLeaf, pCur->pParent,
934 pCur->pParent ? RTListGetNext(&pCur->pParent->ChildListOrLeafEntry, pCur, RTCRX509CERTPATHNODE, SiblingEntry) : NULL,
935 pCur->pParent ? RTListGetPrev(&pCur->pParent->ChildListOrLeafEntry, pCur, RTCRX509CERTPATHNODE, SiblingEntry) : NULL));
936 } while (pCur);
937
938 pThis->pErrInfo = NULL;
939 if (RT_SUCCESS(pThis->rc))
940 return VINF_SUCCESS;
941 }
942 else
943 Assert(RT_FAILURE_NP(pThis->rc));
944 return pThis->rc;
945}
946
947
948/**
949 * Looks up path by leaf/path index.
950 *
951 * @returns Pointer to the leaf node of the path.
952 * @param pThis The path builder & validator instance.
953 * @param iPath The oridnal of the path to get.
954 */
955static PRTCRX509CERTPATHNODE rtCrX509CertPathsGetLeafByIndex(PRTCRX509CERTPATHSINT pThis, uint32_t iPath)
956{
957 Assert(iPath < pThis->cPaths);
958
959 uint32_t iCurPath = 0;
960 PRTCRX509CERTPATHNODE pCurLeaf;
961 RTListForEach(&pThis->LeafList, pCurLeaf, RTCRX509CERTPATHNODE, ChildListOrLeafEntry)
962 {
963 if (iCurPath == iPath)
964 return pCurLeaf;
965 iCurPath++;
966 }
967
968 AssertFailedReturn(NULL);
969}
970
971
972static void rtDumpPrintf(PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser, const char *pszFormat, ...)
973{
974 va_list va;
975 va_start(va, pszFormat);
976 pfnPrintfV(pvUser, pszFormat, va);
977 va_end(va);
978}
979
980
981static void rtDumpIndent(PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser, uint32_t cchSpaces, const char *pszFormat, ...)
982{
983 static const char s_szSpaces[] = " ";
984 while (cchSpaces > 0)
985 {
986 uint32_t cchBurst = RT_MIN(sizeof(s_szSpaces) - 1, cchSpaces);
987 rtDumpPrintf(pfnPrintfV, pvUser, &s_szSpaces[sizeof(s_szSpaces) - cchBurst - 1]);
988 cchSpaces -= cchBurst;
989 }
990
991 va_list va;
992 va_start(va, pszFormat);
993 pfnPrintfV(pvUser, pszFormat, va);
994 va_end(va);
995}
996
997/** @name X.500 attribute types
998 * See RFC-4519 among others.
999 * @{ */
1000#define RTCRX500_ID_AT_OBJECT_CLASS_OID "2.5.4.0"
1001#define RTCRX500_ID_AT_ALIASED_ENTRY_NAME_OID "2.5.4.1"
1002#define RTCRX500_ID_AT_KNOWLDGEINFORMATION_OID "2.5.4.2"
1003#define RTCRX500_ID_AT_COMMON_NAME_OID "2.5.4.3"
1004#define RTCRX500_ID_AT_SURNAME_OID "2.5.4.4"
1005#define RTCRX500_ID_AT_SERIAL_NUMBER_OID "2.5.4.5"
1006#define RTCRX500_ID_AT_COUNTRY_NAME_OID "2.5.4.6"
1007#define RTCRX500_ID_AT_LOCALITY_NAME_OID "2.5.4.7"
1008#define RTCRX500_ID_AT_STATE_OR_PROVINCE_NAME_OID "2.5.4.8"
1009#define RTCRX500_ID_AT_STREET_ADDRESS_OID "2.5.4.9"
1010#define RTCRX500_ID_AT_ORGANIZATION_NAME_OID "2.5.4.10"
1011#define RTCRX500_ID_AT_ORGANIZATION_UNIT_NAME_OID "2.5.4.11"
1012#define RTCRX500_ID_AT_TITLE_OID "2.5.4.12"
1013#define RTCRX500_ID_AT_DESCRIPTION_OID "2.5.4.13"
1014#define RTCRX500_ID_AT_SEARCH_GUIDE_OID "2.5.4.14"
1015#define RTCRX500_ID_AT_BUSINESS_CATEGORY_OID "2.5.4.15"
1016#define RTCRX500_ID_AT_POSTAL_ADDRESS_OID "2.5.4.16"
1017#define RTCRX500_ID_AT_POSTAL_CODE_OID "2.5.4.17"
1018#define RTCRX500_ID_AT_POST_OFFICE_BOX_OID "2.5.4.18"
1019#define RTCRX500_ID_AT_PHYSICAL_DELIVERY_OFFICE_NAME_OID "2.5.4.19"
1020#define RTCRX500_ID_AT_TELEPHONE_NUMBER_OID "2.5.4.20"
1021#define RTCRX500_ID_AT_TELEX_NUMBER_OID "2.5.4.21"
1022#define RTCRX500_ID_AT_TELETEX_TERMINAL_IDENTIFIER_OID "2.5.4.22"
1023#define RTCRX500_ID_AT_FACIMILE_TELEPHONE_NUMBER_OID "2.5.4.23"
1024#define RTCRX500_ID_AT_X121_ADDRESS_OID "2.5.4.24"
1025#define RTCRX500_ID_AT_INTERNATIONAL_ISDN_NUMBER_OID "2.5.4.25"
1026#define RTCRX500_ID_AT_REGISTERED_ADDRESS_OID "2.5.4.26"
1027#define RTCRX500_ID_AT_DESTINATION_INDICATOR_OID "2.5.4.27"
1028#define RTCRX500_ID_AT_PREFERRED_DELIVERY_METHOD_OID "2.5.4.28"
1029#define RTCRX500_ID_AT_PRESENTATION_ADDRESS_OID "2.5.4.29"
1030#define RTCRX500_ID_AT_SUPPORTED_APPLICATION_CONTEXT_OID "2.5.4.30"
1031#define RTCRX500_ID_AT_MEMBER_OID "2.5.4.31"
1032#define RTCRX500_ID_AT_OWNER_OID "2.5.4.32"
1033#define RTCRX500_ID_AT_ROLE_OCCUPANT_OID "2.5.4.33"
1034#define RTCRX500_ID_AT_SEE_ALSO_OID "2.5.4.34"
1035#define RTCRX500_ID_AT_USER_PASSWORD_OID "2.5.4.35"
1036#define RTCRX500_ID_AT_USER_CERTIFICATE_OID "2.5.4.36"
1037#define RTCRX500_ID_AT_CA_CERTIFICATE_OID "2.5.4.37"
1038#define RTCRX500_ID_AT_AUTHORITY_REVOCATION_LIST_OID "2.5.4.38"
1039#define RTCRX500_ID_AT_CERTIFICATE_REVOCATION_LIST_OID "2.5.4.39"
1040#define RTCRX500_ID_AT_CROSS_CERTIFICATE_PAIR_OID "2.5.4.40"
1041#define RTCRX500_ID_AT_NAME_OID "2.5.4.41"
1042#define RTCRX500_ID_AT_GIVEN_NAME_OID "2.5.4.42"
1043#define RTCRX500_ID_AT_INITIALS_OID "2.5.4.43"
1044#define RTCRX500_ID_AT_GENERATION_QUALIFIER_OID "2.5.4.44"
1045#define RTCRX500_ID_AT_UNIQUE_IDENTIFIER_OID "2.5.4.45"
1046#define RTCRX500_ID_AT_DN_QUALIFIER_OID "2.5.4.46"
1047#define RTCRX500_ID_AT_ENHANCHED_SEARCH_GUIDE_OID "2.5.4.47"
1048#define RTCRX500_ID_AT_PROTOCOL_INFORMATION_OID "2.5.4.48"
1049#define RTCRX500_ID_AT_DISTINGUISHED_NAME_OID "2.5.4.49"
1050#define RTCRX500_ID_AT_UNIQUE_MEMBER_OID "2.5.4.50"
1051#define RTCRX500_ID_AT_HOUSE_IDENTIFIER_OID "2.5.4.51"
1052#define RTCRX500_ID_AT_SUPPORTED_ALGORITHMS_OID "2.5.4.52"
1053#define RTCRX500_ID_AT_DELTA_REVOCATION_LIST_OID "2.5.4.53"
1054#define RTCRX500_ID_AT_ATTRIBUTE_CERTIFICATE_OID "2.5.4.58"
1055#define RTCRX500_ID_AT_PSEUDONYM_OID "2.5.4.65"
1056/** @} */
1057
1058
1059static void rtCrX509NameDump(PCRTCRX509NAME pName, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
1060{
1061 for (uint32_t i = 0; i < pName->cItems; i++)
1062 {
1063 PCRTCRX509RELATIVEDISTINGUISHEDNAME const pRdn = pName->papItems[i];
1064 for (uint32_t j = 0; j < pRdn->cItems; j++)
1065 {
1066 PRTCRX509ATTRIBUTETYPEANDVALUE pAttrib = pRdn->papItems[j];
1067
1068 const char *pszType = pAttrib->Type.szObjId;
1069 if ( !strncmp(pAttrib->Type.szObjId, "2.5.4.", 6)
1070 && (pAttrib->Type.szObjId[8] == '\0' || pAttrib->Type.szObjId[9] == '\0'))
1071 {
1072 switch (RTStrToUInt8(&pAttrib->Type.szObjId[6]))
1073 {
1074 case 3: pszType = "cn"; break;
1075 case 4: pszType = "sn"; break;
1076 case 5: pszType = "serialNumber"; break;
1077 case 6: pszType = "c"; break;
1078 case 7: pszType = "l"; break;
1079 case 8: pszType = "st"; break;
1080 case 9: pszType = "street"; break;
1081 case 10: pszType = "o"; break;
1082 case 11: pszType = "ou"; break;
1083 case 13: pszType = "description"; break;
1084 case 15: pszType = "businessCategory"; break;
1085 case 16: pszType = "postalAddress"; break;
1086 case 17: pszType = "postalCode"; break;
1087 case 18: pszType = "postOfficeBox"; break;
1088 case 20: pszType = "telephoneNumber"; break;
1089 case 26: pszType = "registeredAddress"; break;
1090 case 31: pszType = "member"; break;
1091 case 41: pszType = "name"; break;
1092 case 42: pszType = "givenName"; break;
1093 case 43: pszType = "initials"; break;
1094 case 45: pszType = "x500UniqueIdentifier"; break;
1095 case 50: pszType = "uniqueMember"; break;
1096 }
1097 }
1098 rtDumpPrintf(pfnPrintfV, pvUser, "/%s=", pszType);
1099 if (pAttrib->Value.enmType == RTASN1TYPE_STRING)
1100 {
1101 if (pAttrib->Value.u.String.pszUtf8)
1102 rtDumpPrintf(pfnPrintfV, pvUser, "%s", pAttrib->Value.u.String.pszUtf8);
1103 else
1104 {
1105 const char *pch = pAttrib->Value.u.String.Asn1Core.uData.pch;
1106 uint32_t cch = pAttrib->Value.u.String.Asn1Core.cb;
1107 int rc = RTStrValidateEncodingEx(pch, cch, 0);
1108 if (RT_SUCCESS(rc) && cch)
1109 rtDumpPrintf(pfnPrintfV, pvUser, "%.*s", (size_t)cch, pch);
1110 else
1111 while (cch > 0)
1112 {
1113 if (RT_C_IS_PRINT(*pch))
1114 rtDumpPrintf(pfnPrintfV, pvUser, "%c", *pch);
1115 else
1116 rtDumpPrintf(pfnPrintfV, pvUser, "\\x%02x", *pch);
1117 cch--;
1118 pch++;
1119 }
1120 }
1121 }
1122 else
1123 rtDumpPrintf(pfnPrintfV, pvUser, "<not-string: uTag=%#x>", pAttrib->Value.u.Core.uTag);
1124 }
1125 }
1126}
1127
1128
1129static const char *rtCrX509CertPathsNodeGetSourceName(PRTCRX509CERTPATHNODE pNode)
1130{
1131 switch (pNode->uSrc)
1132 {
1133 case RTCRX509CERTPATHNODE_SRC_TARGET: return "target";
1134 case RTCRX509CERTPATHNODE_SRC_UNTRUSTED_SET: return "untrusted_set";
1135 case RTCRX509CERTPATHNODE_SRC_UNTRUSTED_ARRAY: return "untrusted_array";
1136 case RTCRX509CERTPATHNODE_SRC_UNTRUSTED_STORE: return "untrusted_store";
1137 case RTCRX509CERTPATHNODE_SRC_TRUSTED_STORE: return "trusted_store";
1138 case RTCRX509CERTPATHNODE_SRC_TRUSTED_CERT: return "trusted_cert";
1139 default: return "invalid";
1140 }
1141}
1142
1143
1144static void rtCrX509CertPathsDumpOneWorker(PRTCRX509CERTPATHSINT pThis, uint32_t iPath, PRTCRX509CERTPATHNODE pCurLeaf,
1145 uint32_t uVerbosity, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
1146{
1147 RT_NOREF_PV(pThis);
1148 rtDumpPrintf(pfnPrintfV, pvUser, "Path #%u: %s, %u deep, rcVerify=%Rrc\n",
1149 iPath, RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(pCurLeaf->uSrc) ? "trusted" : "untrusted", pCurLeaf->uDepth,
1150 pCurLeaf->rcVerify);
1151
1152 for (uint32_t iIndent = 2; pCurLeaf; iIndent += 2, pCurLeaf = pCurLeaf->pParent)
1153 {
1154 if (pCurLeaf->pCert)
1155 {
1156 rtDumpIndent(pfnPrintfV, pvUser, iIndent, "Issuer : ");
1157 rtCrX509NameDump(&pCurLeaf->pCert->TbsCertificate.Issuer, pfnPrintfV, pvUser);
1158 rtDumpPrintf(pfnPrintfV, pvUser, "\n");
1159
1160 rtDumpIndent(pfnPrintfV, pvUser, iIndent, "Subject: ");
1161 rtCrX509NameDump(&pCurLeaf->pCert->TbsCertificate.Subject, pfnPrintfV, pvUser);
1162 rtDumpPrintf(pfnPrintfV, pvUser, "\n");
1163
1164 if (uVerbosity >= 4)
1165 RTAsn1Dump(&pCurLeaf->pCert->SeqCore.Asn1Core, 0, iIndent, pfnPrintfV, pvUser);
1166 else if (uVerbosity >= 3)
1167 RTAsn1Dump(&pCurLeaf->pCert->TbsCertificate.T3.Extensions.SeqCore.Asn1Core, 0, iIndent, pfnPrintfV, pvUser);
1168 }
1169 else
1170 {
1171 Assert(pCurLeaf->pCertCtx); Assert(pCurLeaf->pCertCtx->pTaInfo);
1172 rtDumpIndent(pfnPrintfV, pvUser, iIndent, "Subject: ");
1173 rtCrX509NameDump(&pCurLeaf->pCertCtx->pTaInfo->CertPath.TaName, pfnPrintfV, pvUser);
1174
1175 if (uVerbosity >= 4)
1176 RTAsn1Dump(&pCurLeaf->pCertCtx->pTaInfo->SeqCore.Asn1Core, 0, iIndent, pfnPrintfV, pvUser);
1177 }
1178
1179 const char *pszSrc = rtCrX509CertPathsNodeGetSourceName(pCurLeaf);
1180 rtDumpIndent(pfnPrintfV, pvUser, iIndent, "Source : %s\n", pszSrc);
1181 }
1182}
1183
1184
1185RTDECL(int) RTCrX509CertPathsDumpOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t uVerbosity,
1186 PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
1187{
1188 /*
1189 * Validate the input.
1190 */
1191 PRTCRX509CERTPATHSINT pThis = hCertPaths;
1192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1193 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
1194 AssertPtrReturn(pfnPrintfV, VERR_INVALID_POINTER);
1195 int rc;
1196 if (iPath < pThis->cPaths)
1197 {
1198 PRTCRX509CERTPATHNODE pLeaf = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
1199 if (pLeaf)
1200 {
1201 rtCrX509CertPathsDumpOneWorker(pThis, iPath, pLeaf, uVerbosity, pfnPrintfV, pvUser);
1202 rc = VINF_SUCCESS;
1203 }
1204 else
1205 rc = VERR_CR_X509_CERTPATHS_INTERNAL_ERROR;
1206 }
1207 else
1208 rc = VERR_NOT_FOUND;
1209 return rc;
1210}
1211
1212
1213RTDECL(int) RTCrX509CertPathsDumpAll(RTCRX509CERTPATHS hCertPaths, uint32_t uVerbosity, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
1214{
1215 /*
1216 * Validate the input.
1217 */
1218 PRTCRX509CERTPATHSINT pThis = hCertPaths;
1219 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1220 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
1221 AssertPtrReturn(pfnPrintfV, VERR_INVALID_POINTER);
1222
1223 /*
1224 * Dump all the paths.
1225 */
1226 rtDumpPrintf(pfnPrintfV, pvUser, "%u paths, rc=%Rrc\n", pThis->cPaths, pThis->rc);
1227 uint32_t iPath = 0;
1228 PRTCRX509CERTPATHNODE pCurLeaf, pNextLeaf;
1229 RTListForEachSafe(&pThis->LeafList, pCurLeaf, pNextLeaf, RTCRX509CERTPATHNODE, ChildListOrLeafEntry)
1230 {
1231 rtCrX509CertPathsDumpOneWorker(pThis, iPath, pCurLeaf, uVerbosity, pfnPrintfV, pvUser);
1232 iPath++;
1233 }
1234
1235 return VINF_SUCCESS;
1236}
1237
1238
1239/** @} */
1240
1241
1242/** @name Path Validator Functions.
1243 * @{
1244 */
1245
1246
1247static void *rtCrX509CpvAllocZ(PRTCRX509CERTPATHSINT pThis, size_t cb, const char *pszWhat)
1248{
1249 void *pv = RTMemAllocZ(cb);
1250 if (!pv)
1251 pThis->rc = RTErrInfoSetF(pThis->pErrInfo, VERR_NO_MEMORY, "Failed to allocate %zu bytes for %s", cb, pszWhat);
1252 return pv;
1253}
1254
1255
1256DECL_NO_INLINE(static, bool) rtCrX509CpvFailed(PRTCRX509CERTPATHSINT pThis, int rc, const char *pszFormat, ...)
1257{
1258 va_list va;
1259 va_start(va, pszFormat);
1260 pThis->rc = RTErrInfoSetV(pThis->pErrInfo, rc, pszFormat, va);
1261 va_end(va);
1262 return false;
1263}
1264
1265
1266/**
1267 * Adds a sequence of excluded sub-trees.
1268 *
1269 * Don't waste time optimizing the output if this is supposed to be a union.
1270 * Unless the path is very long, it's a lot more work to optimize and the result
1271 * will be the same anyway.
1272 *
1273 * @returns success indicator.
1274 * @param pThis The validator instance.
1275 * @param pSubtrees The sequence of sub-trees to add.
1276 */
1277static bool rtCrX509CpvAddExcludedSubtrees(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALSUBTREES pSubtrees)
1278{
1279 if (((pThis->v.cExcludedSubtrees + 1) & 0xf) == 0)
1280 {
1281 void *pvNew = RTMemRealloc(pThis->v.papExcludedSubtrees,
1282 (pThis->v.cExcludedSubtrees + 16) * sizeof(pThis->v.papExcludedSubtrees[0]));
1283 if (RT_UNLIKELY(!pvNew))
1284 return rtCrX509CpvFailed(pThis, VERR_NO_MEMORY, "Error growing subtrees pointer array to %u elements",
1285 pThis->v.cExcludedSubtrees + 16);
1286 pThis->v.papExcludedSubtrees = (PCRTCRX509GENERALSUBTREES *)pvNew;
1287 }
1288 pThis->v.papExcludedSubtrees[pThis->v.cExcludedSubtrees] = pSubtrees;
1289 pThis->v.cExcludedSubtrees++;
1290 return true;
1291}
1292
1293
1294/**
1295 * Checks if a sub-tree is according to RFC-5280.
1296 *
1297 * @returns Success indiciator.
1298 * @param pThis The validator instance.
1299 * @param pSubtree The subtree to check.
1300 */
1301static bool rtCrX509CpvCheckSubtreeValidity(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALSUBTREE pSubtree)
1302{
1303 if ( pSubtree->Base.enmChoice <= RTCRX509GENERALNAMECHOICE_INVALID
1304 || pSubtree->Base.enmChoice >= RTCRX509GENERALNAMECHOICE_END)
1305 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_CHOICE,
1306 "Unexpected GeneralSubtree choice %#x", pSubtree->Base.enmChoice);
1307
1308 if (RTAsn1Integer_UnsignedCompareWithU32(&pSubtree->Minimum, 0) != 0)
1309 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MIN,
1310 "Unexpected GeneralSubtree Minimum value: %#llx",
1311 pSubtree->Minimum.uValue);
1312
1313 if (RTAsn1Integer_IsPresent(&pSubtree->Maximum))
1314 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MAX,
1315 "Unexpected GeneralSubtree Maximum value: %#llx",
1316 pSubtree->Maximum.uValue);
1317
1318 return true;
1319}
1320
1321
1322/**
1323 * Grows the array of permitted sub-trees.
1324 *
1325 * @returns success indiciator.
1326 * @param pThis The validator instance.
1327 * @param cAdding The number of subtrees we should grow by
1328 * (relative to the current number of valid
1329 * entries).
1330 */
1331static bool rtCrX509CpvGrowPermittedSubtrees(PRTCRX509CERTPATHSINT pThis, uint32_t cAdding)
1332{
1333 uint32_t cNew = RT_ALIGN_32(pThis->v.cPermittedSubtrees + cAdding, 16);
1334 if (cNew > pThis->v.cPermittedSubtreesAlloc)
1335 {
1336 if (cNew >= _4K)
1337 return rtCrX509CpvFailed(pThis, VERR_NO_MEMORY, "Too many permitted subtrees: %u (cur %u)",
1338 cNew, pThis->v.cPermittedSubtrees);
1339 void *pvNew = RTMemRealloc(pThis->v.papPermittedSubtrees, cNew * sizeof(pThis->v.papPermittedSubtrees[0]));
1340 if (RT_UNLIKELY(!pvNew))
1341 return rtCrX509CpvFailed(pThis, VERR_NO_MEMORY, "Error growing subtrees pointer array from %u to %u elements",
1342 pThis->v.cPermittedSubtreesAlloc, cNew);
1343 pThis->v.papPermittedSubtrees = (PCRTCRX509GENERALSUBTREE *)pvNew;
1344 }
1345 return true;
1346}
1347
1348
1349/**
1350 * Adds a sequence of permitted sub-trees.
1351 *
1352 * We store reference to each individual sub-tree because we must support
1353 * intersection calculation.
1354 *
1355 * @returns success indiciator.
1356 * @param pThis The validator instance.
1357 * @param cSubtrees The number of sub-trees to add.
1358 * @param papSubtrees Array of sub-trees to add.
1359 */
1360static bool rtCrX509CpvAddPermittedSubtrees(PRTCRX509CERTPATHSINT pThis, uint32_t cSubtrees,
1361 PRTCRX509GENERALSUBTREE const *papSubtrees)
1362{
1363 /*
1364 * If the array is empty, assume no permitted names.
1365 */
1366 if (!cSubtrees)
1367 {
1368 pThis->v.fNoPermittedSubtrees = true;
1369 return true;
1370 }
1371
1372 /*
1373 * Grow the array if necessary.
1374 */
1375 if (!rtCrX509CpvGrowPermittedSubtrees(pThis, cSubtrees))
1376 return false;
1377
1378 /*
1379 * Append each subtree to the array.
1380 */
1381 uint32_t iDst = pThis->v.cPermittedSubtrees;
1382 for (uint32_t iSrc = 0; iSrc < cSubtrees; iSrc++)
1383 {
1384 if (!rtCrX509CpvCheckSubtreeValidity(pThis, papSubtrees[iSrc]))
1385 return false;
1386 pThis->v.papPermittedSubtrees[iDst] = papSubtrees[iSrc];
1387 iDst++;
1388 }
1389 pThis->v.cPermittedSubtrees = iDst;
1390
1391 return true;
1392}
1393
1394
1395/**
1396 * Adds a one permitted sub-tree.
1397 *
1398 * We store reference to each individual sub-tree because we must support
1399 * intersection calculation.
1400 *
1401 * @returns success indiciator.
1402 * @param pThis The validator instance.
1403 * @param pSubtree Array of sub-trees to add.
1404 */
1405static bool rtCrX509CpvAddPermittedSubtree(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALSUBTREE pSubtree)
1406{
1407 return rtCrX509CpvAddPermittedSubtrees(pThis, 1, (PRTCRX509GENERALSUBTREE const *)&pSubtree);
1408}
1409
1410
1411/**
1412 * Calculates the intersection between @a pSubtrees and the current permitted
1413 * sub-trees.
1414 *
1415 * @returns Success indicator.
1416 * @param pThis The validator instance.
1417 * @param pSubtrees The sub-tree sequence to intersect with.
1418 */
1419static bool rtCrX509CpvIntersectionPermittedSubtrees(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALSUBTREES pSubtrees)
1420{
1421 /*
1422 * Deal with special cases first.
1423 */
1424 if (pThis->v.fNoPermittedSubtrees)
1425 {
1426 Assert(pThis->v.cPermittedSubtrees == 0);
1427 return true;
1428 }
1429
1430 uint32_t cRight = pSubtrees->cItems;
1431 PRTCRX509GENERALSUBTREE const *papRight = pSubtrees->papItems;
1432 if (cRight == 0)
1433 {
1434 pThis->v.cPermittedSubtrees = 0;
1435 pThis->v.fNoPermittedSubtrees = true;
1436 return true;
1437 }
1438
1439 uint32_t cLeft = pThis->v.cPermittedSubtrees;
1440 PCRTCRX509GENERALSUBTREE *papLeft = pThis->v.papPermittedSubtrees;
1441 if (!cLeft) /* first name constraint, no initial constraint */
1442 return rtCrX509CpvAddPermittedSubtrees(pThis, cRight, papRight);
1443
1444 /*
1445 * Create a new array with the intersection, freeing the old (left) array
1446 * once we're done.
1447 */
1448 bool afRightTags[RTCRX509GENERALNAMECHOICE_END] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1449
1450 pThis->v.cPermittedSubtrees = 0;
1451 pThis->v.cPermittedSubtreesAlloc = 0;
1452 pThis->v.papPermittedSubtrees = NULL;
1453
1454 for (uint32_t iRight = 0; iRight < cRight; iRight++)
1455 {
1456 if (!rtCrX509CpvCheckSubtreeValidity(pThis, papRight[iRight]))
1457 return false;
1458
1459 RTCRX509GENERALNAMECHOICE const enmRightChoice = papRight[iRight]->Base.enmChoice;
1460 afRightTags[enmRightChoice] = true;
1461
1462 bool fHaveRight = false;
1463 for (uint32_t iLeft = 0; iLeft < cLeft; iLeft++)
1464 if (papLeft[iLeft]->Base.enmChoice == enmRightChoice)
1465 {
1466 if (RTCrX509GeneralSubtree_Compare(papLeft[iLeft], papRight[iRight]) == 0)
1467 {
1468 if (!fHaveRight)
1469 {
1470 fHaveRight = true;
1471 rtCrX509CpvAddPermittedSubtree(pThis, papLeft[iLeft]);
1472 }
1473 }
1474 else if (RTCrX509GeneralSubtree_ConstraintMatch(papLeft[iLeft], papRight[iRight]))
1475 {
1476 if (!fHaveRight)
1477 {
1478 fHaveRight = true;
1479 rtCrX509CpvAddPermittedSubtree(pThis, papRight[iRight]);
1480 }
1481 }
1482 else if (RTCrX509GeneralSubtree_ConstraintMatch(papRight[iRight], papLeft[iLeft]))
1483 rtCrX509CpvAddPermittedSubtree(pThis, papLeft[iLeft]);
1484 }
1485 }
1486
1487 /*
1488 * Add missing types not specified in the right set.
1489 */
1490 for (uint32_t iLeft = 0; iLeft < cLeft; iLeft++)
1491 if (!afRightTags[papLeft[iLeft]->Base.enmChoice])
1492 rtCrX509CpvAddPermittedSubtree(pThis, papLeft[iLeft]);
1493
1494 /*
1495 * If we ended up with an empty set, no names are permitted any more.
1496 */
1497 if (pThis->v.cPermittedSubtrees == 0)
1498 pThis->v.fNoPermittedSubtrees = true;
1499
1500 RTMemFree(papLeft);
1501 return RT_SUCCESS(pThis->rc);
1502}
1503
1504
1505/**
1506 * Check if the given X.509 name is permitted by current name constraints.
1507 *
1508 * @returns true is permitteded, false if not (caller set error info).
1509 * @param pThis The validator instance.
1510 * @param pName The name to match.
1511 */
1512static bool rtCrX509CpvIsNamePermitted(PRTCRX509CERTPATHSINT pThis, PCRTCRX509NAME pName)
1513{
1514 uint32_t i = pThis->v.cPermittedSubtrees;
1515 if (i == 0)
1516 return !pThis->v.fNoPermittedSubtrees;
1517
1518 while (i-- > 0)
1519 {
1520 PCRTCRX509GENERALSUBTREE pConstraint = pThis->v.papPermittedSubtrees[i];
1521 if ( RTCRX509GENERALNAME_IS_DIRECTORY_NAME(&pConstraint->Base)
1522 && RTCrX509Name_ConstraintMatch(&pConstraint->Base.u.pT4->DirectoryName, pName))
1523 return true;
1524 }
1525 return false;
1526}
1527
1528
1529/**
1530 * Check if the given X.509 general name is permitted by current name
1531 * constraints.
1532 *
1533 * @returns true is permitteded, false if not (caller sets error info).
1534 * @param pThis The validator instance.
1535 * @param pGeneralName The name to match.
1536 */
1537static bool rtCrX509CpvIsGeneralNamePermitted(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALNAME pGeneralName)
1538{
1539 uint32_t i = pThis->v.cPermittedSubtrees;
1540 if (i == 0)
1541 return !pThis->v.fNoPermittedSubtrees;
1542
1543 while (i-- > 0)
1544 if (RTCrX509GeneralName_ConstraintMatch(&pThis->v.papPermittedSubtrees[i]->Base, pGeneralName))
1545 return true;
1546 return false;
1547}
1548
1549
1550/**
1551 * Check if the given X.509 name is excluded by current name constraints.
1552 *
1553 * @returns true if excluded (caller sets error info), false if not explicitly
1554 * excluded.
1555 * @param pThis The validator instance.
1556 * @param pName The name to match.
1557 */
1558static bool rtCrX509CpvIsNameExcluded(PRTCRX509CERTPATHSINT pThis, PCRTCRX509NAME pName)
1559{
1560 uint32_t i = pThis->v.cExcludedSubtrees;
1561 while (i-- > 0)
1562 {
1563 PCRTCRX509GENERALSUBTREES pSubTrees = pThis->v.papExcludedSubtrees[i];
1564 uint32_t j = pSubTrees->cItems;
1565 while (j-- > 0)
1566 {
1567 PCRTCRX509GENERALSUBTREE const pSubTree = pSubTrees->papItems[j];
1568 if ( RTCRX509GENERALNAME_IS_DIRECTORY_NAME(&pSubTree->Base)
1569 && RTCrX509Name_ConstraintMatch(&pSubTree->Base.u.pT4->DirectoryName, pName))
1570 return true;
1571 }
1572 }
1573 return false;
1574}
1575
1576
1577/**
1578 * Check if the given X.509 general name is excluded by current name
1579 * constraints.
1580 *
1581 * @returns true if excluded (caller sets error info), false if not explicitly
1582 * excluded.
1583 * @param pThis The validator instance.
1584 * @param pGeneralName The name to match.
1585 */
1586static bool rtCrX509CpvIsGeneralNameExcluded(PRTCRX509CERTPATHSINT pThis, PCRTCRX509GENERALNAME pGeneralName)
1587{
1588 uint32_t i = pThis->v.cExcludedSubtrees;
1589 while (i-- > 0)
1590 {
1591 PCRTCRX509GENERALSUBTREES pSubTrees = pThis->v.papExcludedSubtrees[i];
1592 uint32_t j = pSubTrees->cItems;
1593 while (j-- > 0)
1594 if (RTCrX509GeneralName_ConstraintMatch(&pSubTrees->papItems[j]->Base, pGeneralName))
1595 return true;
1596 }
1597 return false;
1598}
1599
1600
1601/**
1602 * Creates a new node and inserts it.
1603 *
1604 * @param pThis The path builder & validator instance.
1605 * @param pParent The parent node. NULL for the root node.
1606 * @param iDepth The tree depth to insert at.
1607 * @param pValidPolicy The valid policy of the new node.
1608 * @param pQualifiers The qualifiers of the new node.
1609 * @param pExpectedPolicy The (first) expected polcy of the new node.
1610 */
1611static bool rtCrX509CpvPolicyTreeInsertNew(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHSPOLICYNODE pParent, uint32_t iDepth,
1612 PCRTASN1OBJID pValidPolicy, PCRTCRX509POLICYQUALIFIERINFOS pQualifiers,
1613 PCRTASN1OBJID pExpectedPolicy)
1614{
1615 Assert(iDepth <= pThis->v.cNodes);
1616
1617 PRTCRX509CERTPATHSPOLICYNODE pNode;
1618 pNode = (PRTCRX509CERTPATHSPOLICYNODE)rtCrX509CpvAllocZ(pThis, sizeof(*pNode), "policy tree node");
1619 if (pNode)
1620 {
1621 pNode->pParent = pParent;
1622 if (pParent)
1623 RTListAppend(&pParent->ChildList, &pNode->SiblingEntry);
1624 else
1625 {
1626 Assert(pThis->v.pValidPolicyTree == NULL);
1627 pThis->v.pValidPolicyTree = pNode;
1628 RTListInit(&pNode->SiblingEntry);
1629 }
1630 RTListInit(&pNode->ChildList);
1631 RTListAppend(&pThis->v.paValidPolicyDepthLists[iDepth], &pNode->DepthEntry);
1632
1633 pNode->pValidPolicy = pValidPolicy;
1634 pNode->pPolicyQualifiers = pQualifiers;
1635 pNode->pExpectedPolicyFirst = pExpectedPolicy;
1636 pNode->cMoreExpectedPolicySet = 0;
1637 pNode->papMoreExpectedPolicySet = NULL;
1638 return true;
1639 }
1640 return false;
1641}
1642
1643
1644/**
1645 * Unlinks and frees a node in the valid policy tree.
1646 *
1647 * @param pThis The path builder & validator instance.
1648 * @param pNode The node to destroy.
1649 */
1650static void rtCrX509CpvPolicyTreeDestroyNode(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHSPOLICYNODE pNode)
1651{
1652 Assert(RTListIsEmpty(&pNode->ChildList));
1653 if (pNode->pParent)
1654 RTListNodeRemove(&pNode->SiblingEntry);
1655 else
1656 pThis->v.pValidPolicyTree = NULL;
1657 RTListNodeRemove(&pNode->DepthEntry);
1658 pNode->pParent = NULL;
1659
1660 if (pNode->papMoreExpectedPolicySet)
1661 {
1662 RTMemFree(pNode->papMoreExpectedPolicySet);
1663 pNode->papMoreExpectedPolicySet = NULL;
1664 }
1665 RTMemFree(pNode);
1666}
1667
1668
1669/**
1670 * Unlinks and frees a sub-tree in the valid policy tree.
1671 *
1672 * @param pThis The path builder & validator instance.
1673 * @param pNode The node that is the root of the subtree.
1674 */
1675static void rtCrX509CpvPolicyTreeDestroySubtree(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHSPOLICYNODE pNode)
1676{
1677 if (!RTListIsEmpty(&pNode->ChildList))
1678 {
1679 PRTCRX509CERTPATHSPOLICYNODE pCur = pNode;
1680 do
1681 {
1682 Assert(!RTListIsEmpty(&pCur->ChildList));
1683
1684 /* Decend until we find a leaf. */
1685 do
1686 pCur = RTListGetFirst(&pCur->ChildList, RTCRX509CERTPATHSPOLICYNODE, SiblingEntry);
1687 while (!RTListIsEmpty(&pCur->ChildList));
1688
1689 /* Remove it and all leafy siblings. */
1690 PRTCRX509CERTPATHSPOLICYNODE pParent = pCur->pParent;
1691 do
1692 {
1693 Assert(pCur != pNode);
1694 rtCrX509CpvPolicyTreeDestroyNode(pThis, pCur);
1695 pCur = RTListGetFirst(&pParent->ChildList, RTCRX509CERTPATHSPOLICYNODE, SiblingEntry);
1696 if (!pCur)
1697 {
1698 pCur = pParent;
1699 pParent = pParent->pParent;
1700 }
1701 } while (RTListIsEmpty(&pCur->ChildList) && pCur != pNode);
1702 } while (pCur != pNode);
1703 }
1704
1705 rtCrX509CpvPolicyTreeDestroyNode(pThis, pNode);
1706}
1707
1708
1709
1710/**
1711 * Destroys the entire policy tree.
1712 *
1713 * @param pThis The path builder & validator instance.
1714 */
1715static void rtCrX509CpvPolicyTreeDestroy(PRTCRX509CERTPATHSINT pThis)
1716{
1717 uint32_t i = pThis->v.cNodes + 1;
1718 while (i-- > 0)
1719 {
1720 PRTCRX509CERTPATHSPOLICYNODE pCur, pNext;
1721 RTListForEachSafe(&pThis->v.paValidPolicyDepthLists[i], pCur, pNext, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
1722 {
1723 rtCrX509CpvPolicyTreeDestroyNode(pThis, pCur);
1724 }
1725 }
1726}
1727
1728
1729/**
1730 * Removes all leaf nodes at level @a iDepth and above.
1731 *
1732 * @param pThis The path builder & validator instance.
1733 * @param iDepth The depth to start pruning at.
1734 */
1735static void rtCrX509CpvPolicyTreePrune(PRTCRX509CERTPATHSINT pThis, uint32_t iDepth)
1736{
1737 do
1738 {
1739 PRTLISTANCHOR pList = &pThis->v.paValidPolicyDepthLists[iDepth];
1740 PRTCRX509CERTPATHSPOLICYNODE pCur, pNext;
1741 RTListForEachSafe(pList, pCur, pNext, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
1742 {
1743 if (RTListIsEmpty(&pCur->ChildList))
1744 rtCrX509CpvPolicyTreeDestroyNode(pThis, pCur);
1745 }
1746
1747 } while (iDepth-- > 0);
1748}
1749
1750
1751/**
1752 * Checks if @a pPolicy is the valid policy of a child of @a pNode.
1753 *
1754 * @returns true if in child node, false if not.
1755 * @param pNode The node which children to check.
1756 * @param pPolicy The valid policy to look for among the children.
1757 */
1758static bool rtCrX509CpvPolicyTreeIsChild(PRTCRX509CERTPATHSPOLICYNODE pNode, PCRTASN1OBJID pPolicy)
1759{
1760 PRTCRX509CERTPATHSPOLICYNODE pChild;
1761 RTListForEach(&pNode->ChildList, pChild, RTCRX509CERTPATHSPOLICYNODE, SiblingEntry)
1762 {
1763 if (RTAsn1ObjId_Compare(pChild->pValidPolicy, pPolicy) == 0)
1764 return true;
1765 }
1766 return true;
1767}
1768
1769
1770/**
1771 * Prunes the valid policy tree according to the specified user policy set.
1772 *
1773 * @returns Pointer to the policy object from @a papPolicies if found, NULL if
1774 * no match.
1775 * @param pObjId The object ID to locate at match in the set.
1776 * @param cPolicies The number of policies in @a papPolicies.
1777 * @param papPolicies The policy set to search.
1778 */
1779static PCRTASN1OBJID rtCrX509CpvFindObjIdInPolicySet(PCRTASN1OBJID pObjId, uint32_t cPolicies, PCRTASN1OBJID *papPolicies)
1780{
1781 uint32_t i = cPolicies;
1782 while (i-- > 0)
1783 if (RTAsn1ObjId_Compare(pObjId, papPolicies[i]) == 0)
1784 return papPolicies[i];
1785 return NULL;
1786}
1787
1788
1789/**
1790 * Prunes the valid policy tree according to the specified user policy set.
1791 *
1792 * @returns success indicator (allocates memory)
1793 * @param pThis The path builder & validator instance.
1794 * @param cPolicies The number of policies in @a papPolicies.
1795 * @param papPolicies The user initial policies.
1796 */
1797static bool rtCrX509CpvPolicyTreeIntersect(PRTCRX509CERTPATHSINT pThis, uint32_t cPolicies, PCRTASN1OBJID *papPolicies)
1798{
1799 /*
1800 * 4.1.6.g.i - NULL tree remains NULL.
1801 */
1802 if (!pThis->v.pValidPolicyTree)
1803 return true;
1804
1805 /*
1806 * 4.1.6.g.ii - If the user set includes anyPolicy, the whole tree is the
1807 * result of the intersection.
1808 */
1809 uint32_t i = cPolicies;
1810 while (i-- > 0)
1811 if (RTAsn1ObjId_CompareWithString(papPolicies[i], RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
1812 return true;
1813
1814 /*
1815 * 4.1.6.g.iii - Complicated.
1816 */
1817 PRTCRX509CERTPATHSPOLICYNODE pCur, pNext;
1818 PRTLISTANCHOR pList;
1819
1820 /* 1 & 2: Delete nodes which parent has valid policy == anyPolicy and which
1821 valid policy is neither anyPolicy nor a member of papszPolicies.
1822 While doing so, construct a set of unused user policies that
1823 we'll replace anyPolicy nodes with in step 3. */
1824 uint32_t cPoliciesLeft = 0;
1825 PCRTASN1OBJID *papPoliciesLeft = NULL;
1826 if (cPolicies)
1827 {
1828 papPoliciesLeft = (PCRTASN1OBJID *)rtCrX509CpvAllocZ(pThis, cPolicies * sizeof(papPoliciesLeft[0]), "papPoliciesLeft");
1829 if (!papPoliciesLeft)
1830 return false;
1831 for (i = 0; i < cPolicies; i++)
1832 papPoliciesLeft[i] = papPolicies[i];
1833 }
1834
1835 for (uint32_t iDepth = 1; iDepth <= pThis->v.cNodes; iDepth++)
1836 {
1837 pList = &pThis->v.paValidPolicyDepthLists[iDepth];
1838 RTListForEachSafe(pList, pCur, pNext, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
1839 {
1840 Assert(pCur->pParent);
1841 if ( RTAsn1ObjId_CompareWithString(pCur->pParent->pValidPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0
1842 && RTAsn1ObjId_CompareWithString(pCur->pValidPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) != 0)
1843 {
1844 PCRTASN1OBJID pFound = rtCrX509CpvFindObjIdInPolicySet(pCur->pValidPolicy, cPolicies, papPolicies);
1845 if (!pFound)
1846 rtCrX509CpvPolicyTreeDestroySubtree(pThis, pCur);
1847 else
1848 for (i = 0; i < cPoliciesLeft; i++)
1849 if (papPoliciesLeft[i] == pFound)
1850 {
1851 cPoliciesLeft--;
1852 if (i < cPoliciesLeft)
1853 papPoliciesLeft[i] = papPoliciesLeft[cPoliciesLeft];
1854 papPoliciesLeft[cPoliciesLeft] = NULL;
1855 break;
1856 }
1857 }
1858 }
1859 }
1860
1861 /*
1862 * 4.1.5.g.iii.3 - Replace anyPolicy nodes on the final tree depth with
1863 * the policies in papPoliciesLeft.
1864 */
1865 pList = &pThis->v.paValidPolicyDepthLists[pThis->v.cNodes];
1866 RTListForEachSafe(pList, pCur, pNext, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
1867 {
1868 if (RTAsn1ObjId_CompareWithString(pCur->pValidPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
1869 {
1870 for (i = 0; i < cPoliciesLeft; i++)
1871 rtCrX509CpvPolicyTreeInsertNew(pThis, pCur->pParent, pThis->v.cNodes - 1,
1872 papPoliciesLeft[i], pCur->pPolicyQualifiers, papPoliciesLeft[i]);
1873 rtCrX509CpvPolicyTreeDestroyNode(pThis, pCur);
1874 }
1875 }
1876
1877 RTMemFree(papPoliciesLeft);
1878
1879 /*
1880 * 4.1.5.g.iii.4 - Prune the tree
1881 */
1882 rtCrX509CpvPolicyTreePrune(pThis, pThis->v.cNodes - 1);
1883
1884 return RT_SUCCESS(pThis->rc);
1885}
1886
1887
1888
1889/**
1890 * Frees the path validator state.
1891 *
1892 * @param pThis The path builder & validator instance.
1893 */
1894static void rtCrX509CpvCleanup(PRTCRX509CERTPATHSINT pThis)
1895{
1896 /*
1897 * Destroy the policy tree and all its nodes. We do this from the bottom
1898 * up via the depth lists, saving annoying tree traversal.
1899 */
1900 if (pThis->v.paValidPolicyDepthLists)
1901 {
1902 rtCrX509CpvPolicyTreeDestroy(pThis);
1903
1904 RTMemFree(pThis->v.paValidPolicyDepthLists);
1905 pThis->v.paValidPolicyDepthLists = NULL;
1906 }
1907
1908 Assert(pThis->v.pValidPolicyTree == NULL);
1909 pThis->v.pValidPolicyTree = NULL;
1910
1911 /*
1912 * Destroy the name constraint arrays.
1913 */
1914 if (pThis->v.papPermittedSubtrees)
1915 {
1916 RTMemFree(pThis->v.papPermittedSubtrees);
1917 pThis->v.papPermittedSubtrees = NULL;
1918 }
1919 pThis->v.cPermittedSubtrees = 0;
1920 pThis->v.cPermittedSubtreesAlloc = 0;
1921 pThis->v.fNoPermittedSubtrees = false;
1922
1923 if (pThis->v.papExcludedSubtrees)
1924 {
1925 RTMemFree(pThis->v.papExcludedSubtrees);
1926 pThis->v.papExcludedSubtrees = NULL;
1927 }
1928 pThis->v.cExcludedSubtrees = 0;
1929
1930 /*
1931 * Clear other pointers.
1932 */
1933 pThis->v.pWorkingIssuer = NULL;
1934 pThis->v.pWorkingPublicKey = NULL;
1935 pThis->v.pWorkingPublicKeyAlgorithm = NULL;
1936 pThis->v.pWorkingPublicKeyParameters = NULL;
1937}
1938
1939
1940
1941/**
1942 * Initializes the state.
1943 *
1944 * Caller must check pThis->rc.
1945 *
1946 * @param pThis The path builder & validator instance.
1947 * @param pTrustAnchor The trust anchor node for the path that we're about
1948 * to validate.
1949 */
1950static void rtCrX509CpvInit(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pTrustAnchor)
1951{
1952 rtCrX509CpvCleanup(pThis);
1953
1954 /*
1955 * The node count does not include the trust anchor.
1956 */
1957 pThis->v.cNodes = pTrustAnchor->uDepth;
1958
1959 /*
1960 * Valid policy tree starts with an anyPolicy node.
1961 */
1962 uint32_t i = pThis->v.cNodes + 1;
1963 pThis->v.paValidPolicyDepthLists = (PRTLISTANCHOR)rtCrX509CpvAllocZ(pThis, i * sizeof(RTLISTANCHOR),
1964 "paValidPolicyDepthLists");
1965 if (RT_UNLIKELY(!pThis->v.paValidPolicyDepthLists))
1966 return;
1967 while (i-- > 0)
1968 RTListInit(&pThis->v.paValidPolicyDepthLists[i]);
1969
1970 if (!rtCrX509CpvPolicyTreeInsertNew(pThis, NULL, 0 /* iDepth*/, &pThis->AnyPolicyObjId, NULL, &pThis->AnyPolicyObjId))
1971 return;
1972 Assert(!RTListIsEmpty(&pThis->v.paValidPolicyDepthLists[0])); Assert(pThis->v.pValidPolicyTree);
1973
1974 /*
1975 * Name constrains.
1976 */
1977 if (pThis->pInitialPermittedSubtrees)
1978 rtCrX509CpvAddPermittedSubtrees(pThis, pThis->pInitialPermittedSubtrees->cItems,
1979 pThis->pInitialPermittedSubtrees->papItems);
1980 if (pThis->pInitialExcludedSubtrees)
1981 rtCrX509CpvAddExcludedSubtrees(pThis, pThis->pInitialExcludedSubtrees);
1982
1983 /*
1984 * Counters.
1985 */
1986 pThis->v.cExplicitPolicy = pThis->cInitialExplicitPolicy;
1987 pThis->v.cInhibitPolicyMapping = pThis->cInitialPolicyMappingInhibit;
1988 pThis->v.cInhibitAnyPolicy = pThis->cInitialInhibitAnyPolicy;
1989 pThis->v.cMaxPathLength = pThis->v.cNodes;
1990
1991 /*
1992 * Certificate info from the trust anchor.
1993 */
1994 if (pTrustAnchor->pCert)
1995 {
1996 PCRTCRX509TBSCERTIFICATE const pTbsCert = &pTrustAnchor->pCert->TbsCertificate;
1997 pThis->v.pWorkingIssuer = &pTbsCert->Subject;
1998 pThis->v.pWorkingPublicKey = &pTbsCert->SubjectPublicKeyInfo.SubjectPublicKey;
1999 pThis->v.pWorkingPublicKeyAlgorithm = &pTbsCert->SubjectPublicKeyInfo.Algorithm.Algorithm;
2000 pThis->v.pWorkingPublicKeyParameters = &pTbsCert->SubjectPublicKeyInfo.Algorithm.Parameters;
2001 }
2002 else
2003 {
2004 Assert(pTrustAnchor->pCertCtx); Assert(pTrustAnchor->pCertCtx->pTaInfo);
2005
2006 PCRTCRTAFTRUSTANCHORINFO const pTaInfo = pTrustAnchor->pCertCtx->pTaInfo;
2007 pThis->v.pWorkingIssuer = &pTaInfo->CertPath.TaName;
2008 pThis->v.pWorkingPublicKey = &pTaInfo->PubKey.SubjectPublicKey;
2009 pThis->v.pWorkingPublicKeyAlgorithm = &pTaInfo->PubKey.Algorithm.Algorithm;
2010 pThis->v.pWorkingPublicKeyParameters = &pTaInfo->PubKey.Algorithm.Parameters;
2011 }
2012 if ( !RTASN1CORE_IS_PRESENT(&pThis->v.pWorkingPublicKeyParameters->u.Core)
2013 || pThis->v.pWorkingPublicKeyParameters->enmType == RTASN1TYPE_NULL)
2014 pThis->v.pWorkingPublicKeyParameters = NULL;
2015}
2016
2017
2018/**
2019 * Step 6.1.3.a.
2020 */
2021static bool rtCrX509CpvCheckBasicCertInfo(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
2022{
2023 /*
2024 * 6.1.3.a.1 - Verify the certificate signature.
2025 */
2026 int rc = RTCrX509Certificate_VerifySignature(pNode->pCert, pThis->v.pWorkingPublicKeyAlgorithm,
2027 pThis->v.pWorkingPublicKeyParameters, pThis->v.pWorkingPublicKey,
2028 pThis->pErrInfo);
2029 if (RT_FAILURE(rc))
2030 {
2031 pThis->rc = rc;
2032 return false;
2033 }
2034
2035 /*
2036 * 6.1.3.a.2 - Verify that the certificate is valid at the specified time.
2037 */
2038 AssertCompile(sizeof(pThis->szTmp) >= 36 * 3);
2039 if ( (pThis->fFlags & RTCRX509CERTPATHSINT_F_VALID_TIME)
2040 && !RTCrX509Validity_IsValidAtTimeSpec(&pNode->pCert->TbsCertificate.Validity, &pThis->ValidTime))
2041 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NOT_VALID_AT_TIME,
2042 "Certificate is not valid (ValidTime=%s Validity=[%s...%s])",
2043 RTTimeSpecToString(&pThis->ValidTime, &pThis->szTmp[0], 36),
2044 RTTimeToString(&pNode->pCert->TbsCertificate.Validity.NotBefore.Time, &pThis->szTmp[36], 36),
2045 RTTimeToString(&pNode->pCert->TbsCertificate.Validity.NotAfter.Time, &pThis->szTmp[2*36], 36) );
2046
2047 /*
2048 * 6.1.3.a.3 - Verified that the certficiate is not revoked.
2049 */
2050 /** @todo rainy day. */
2051
2052 /*
2053 * 6.1.3.a.4 - Check the issuer name.
2054 */
2055 if (!RTCrX509Name_MatchByRfc5280(&pNode->pCert->TbsCertificate.Issuer, pThis->v.pWorkingIssuer))
2056 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_ISSUER_MISMATCH, "Issuer mismatch");
2057
2058 return true;
2059}
2060
2061
2062/**
2063 * Step 6.1.3.b-c.
2064 */
2065static bool rtCrX509CpvCheckNameConstraints(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
2066{
2067 if (pThis->v.fNoPermittedSubtrees)
2068 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NO_PERMITTED_NAMES, "No permitted subtrees");
2069
2070 if ( pNode->pCert->TbsCertificate.Subject.cItems > 0
2071 && ( !rtCrX509CpvIsNamePermitted(pThis, &pNode->pCert->TbsCertificate.Subject)
2072 || rtCrX509CpvIsNameExcluded(pThis, &pNode->pCert->TbsCertificate.Subject)) )
2073 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NAME_NOT_PERMITTED,
2074 "Subject name is not permitted by current name constraints");
2075
2076 PCRTCRX509GENERALNAMES pAltSubjectName = pNode->pCert->TbsCertificate.T3.pAltSubjectName;
2077 if (pAltSubjectName)
2078 {
2079 uint32_t i = pAltSubjectName->cItems;
2080 while (i-- > 0)
2081 if ( !rtCrX509CpvIsGeneralNamePermitted(pThis, pAltSubjectName->papItems[i])
2082 || rtCrX509CpvIsGeneralNameExcluded(pThis, pAltSubjectName->papItems[i]))
2083 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_ALT_NAME_NOT_PERMITTED,
2084 "Alternative name #%u is is not permitted by current name constraints", i);
2085 }
2086
2087 return true;
2088}
2089
2090
2091/**
2092 * Step 6.1.3.d-f.
2093 */
2094static bool rtCrX509CpvWorkValidPolicyTree(PRTCRX509CERTPATHSINT pThis, uint32_t iDepth, PRTCRX509CERTPATHNODE pNode,
2095 bool fSelfIssued)
2096{
2097 PCRTCRX509CERTIFICATEPOLICIES pPolicies = pNode->pCert->TbsCertificate.T3.pCertificatePolicies;
2098 if (pPolicies)
2099 {
2100 /*
2101 * 6.1.3.d.1 - Work the certiciate policies into the tree.
2102 */
2103 PRTCRX509CERTPATHSPOLICYNODE pCur;
2104 PRTLISTANCHOR pListAbove = &pThis->v.paValidPolicyDepthLists[iDepth - 1];
2105 uint32_t iAnyPolicy = UINT32_MAX;
2106 uint32_t i = pPolicies->cItems;
2107 while (i-- > 0)
2108 {
2109 PCRTCRX509POLICYQUALIFIERINFOS const pQualifiers = &pPolicies->papItems[i]->PolicyQualifiers;
2110 PCRTASN1OBJID const pIdP = &pPolicies->papItems[i]->PolicyIdentifier;
2111 if (RTAsn1ObjId_CompareWithString(pIdP, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
2112 {
2113 iAnyPolicy++;
2114 continue;
2115 }
2116
2117 /*
2118 * 6.1.3.d.1.i - Create children for matching policies.
2119 */
2120 uint32_t cMatches = 0;
2121 RTListForEach(pListAbove, pCur, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2122 {
2123 bool fMatch = RTAsn1ObjId_Compare(pCur->pExpectedPolicyFirst, pIdP) == 0;
2124 if (!fMatch && pCur->cMoreExpectedPolicySet)
2125 for (uint32_t j = 0; !fMatch && j < pCur->cMoreExpectedPolicySet; j++)
2126 fMatch = RTAsn1ObjId_Compare(pCur->papMoreExpectedPolicySet[j], pIdP) == 0;
2127 if (fMatch)
2128 {
2129 if (!rtCrX509CpvPolicyTreeInsertNew(pThis, pCur, iDepth, pIdP, pQualifiers, pIdP))
2130 return false;
2131 cMatches++;
2132 }
2133 }
2134
2135 /*
2136 * 6.1.3.d.1.ii - If no matches above do the same for anyPolicy
2137 * nodes, only match with valid policy this time.
2138 */
2139 if (cMatches == 0)
2140 {
2141 RTListForEach(pListAbove, pCur, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2142 {
2143 if (RTAsn1ObjId_CompareWithString(pCur->pExpectedPolicyFirst, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
2144 {
2145 if (!rtCrX509CpvPolicyTreeInsertNew(pThis, pCur, iDepth, pIdP, pQualifiers, pIdP))
2146 return false;
2147 }
2148 }
2149 }
2150 }
2151
2152 /*
2153 * 6.1.3.d.2 - If anyPolicy present, make sure all expected policies
2154 * are propagated to the current depth.
2155 */
2156 if ( iAnyPolicy < pPolicies->cItems
2157 && ( pThis->v.cInhibitAnyPolicy > 0
2158 || (pNode->pParent && fSelfIssued) ) )
2159 {
2160 PCRTCRX509POLICYQUALIFIERINFOS pApQ = &pPolicies->papItems[iAnyPolicy]->PolicyQualifiers;
2161 RTListForEach(pListAbove, pCur, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2162 {
2163 if (!rtCrX509CpvPolicyTreeIsChild(pCur, pCur->pExpectedPolicyFirst))
2164 rtCrX509CpvPolicyTreeInsertNew(pThis, pCur, iDepth, pCur->pExpectedPolicyFirst, pApQ,
2165 pCur->pExpectedPolicyFirst);
2166 for (uint32_t j = 0; j < pCur->cMoreExpectedPolicySet; j++)
2167 if (!rtCrX509CpvPolicyTreeIsChild(pCur, pCur->papMoreExpectedPolicySet[j]))
2168 rtCrX509CpvPolicyTreeInsertNew(pThis, pCur, iDepth, pCur->papMoreExpectedPolicySet[j], pApQ,
2169 pCur->papMoreExpectedPolicySet[j]);
2170 }
2171 }
2172 /*
2173 * 6.1.3.d.3 - Prune the tree.
2174 */
2175 else
2176 rtCrX509CpvPolicyTreePrune(pThis, iDepth - 1);
2177 }
2178 else
2179 {
2180 /*
2181 * 6.1.3.e - No policy extension present, set tree to NULL.
2182 */
2183 rtCrX509CpvPolicyTreeDestroy(pThis);
2184 }
2185
2186 /*
2187 * 6.1.3.f - NULL tree check.
2188 */
2189 if ( pThis->v.pValidPolicyTree == NULL
2190 && pThis->v.cExplicitPolicy == 0)
2191 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NO_VALID_POLICY,
2192 "An explicit policy is called for but the valid policy tree is NULL.");
2193 return RT_SUCCESS(pThis->rc);
2194}
2195
2196
2197/**
2198 * Step 6.1.4.a-b.
2199 */
2200static bool rtCrX509CpvSoakUpPolicyMappings(PRTCRX509CERTPATHSINT pThis, uint32_t iDepth,
2201 PCRTCRX509POLICYMAPPINGS pPolicyMappings)
2202{
2203 /*
2204 * 6.1.4.a - The anyPolicy is not allowed in policy mappings as it would
2205 * allow an evil intermediate certificate to expand the policy
2206 * scope of a certiciate chain without regard to upstream.
2207 */
2208 uint32_t i = pPolicyMappings->cItems;
2209 while (i-- > 0)
2210 {
2211 PCRTCRX509POLICYMAPPING const pOne = pPolicyMappings->papItems[i];
2212 if (RTAsn1ObjId_CompareWithString(&pOne->IssuerDomainPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
2213 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_INVALID_POLICY_MAPPING,
2214 "Invalid policy mapping %#u: IssuerDomainPolicy is anyPolicy.", i);
2215
2216 if (RTAsn1ObjId_CompareWithString(&pOne->SubjectDomainPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
2217 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_INVALID_POLICY_MAPPING,
2218 "Invalid policy mapping %#u: SubjectDomainPolicy is anyPolicy.", i);
2219 }
2220
2221 PRTCRX509CERTPATHSPOLICYNODE pCur, pNext;
2222 if (pThis->v.cInhibitPolicyMapping > 0)
2223 {
2224 /*
2225 * 6.1.4.b.1 - Do the policy mapping.
2226 */
2227 i = pPolicyMappings->cItems;
2228 while (i-- > 0)
2229 {
2230 PCRTCRX509POLICYMAPPING const pOne = pPolicyMappings->papItems[i];
2231
2232 uint32_t cFound = 0;
2233 RTListForEach(&pThis->v.paValidPolicyDepthLists[iDepth], pCur, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2234 {
2235 if (RTAsn1ObjId_Compare(pCur->pValidPolicy, &pOne->IssuerDomainPolicy))
2236 {
2237 if (!pCur->fAlreadyMapped)
2238 {
2239 pCur->fAlreadyMapped = true;
2240 pCur->pExpectedPolicyFirst = &pOne->SubjectDomainPolicy;
2241 }
2242 else
2243 {
2244 uint32_t iExpected = pCur->cMoreExpectedPolicySet;
2245 void *pvNew = RTMemRealloc(pCur->papMoreExpectedPolicySet,
2246 sizeof(pCur->papMoreExpectedPolicySet[0]) * (iExpected + 1));
2247 if (!pvNew)
2248 return rtCrX509CpvFailed(pThis, VERR_NO_MEMORY,
2249 "Error growing papMoreExpectedPolicySet array (cur %u, depth %u)",
2250 pCur->cMoreExpectedPolicySet, iDepth);
2251 pCur->papMoreExpectedPolicySet = (PCRTASN1OBJID *)pvNew;
2252 pCur->papMoreExpectedPolicySet[iExpected] = &pOne->SubjectDomainPolicy;
2253 pCur->cMoreExpectedPolicySet = iExpected + 1;
2254 }
2255 cFound++;
2256 }
2257 }
2258
2259 /*
2260 * If no mapping took place, look for an anyPolicy node.
2261 */
2262 if (!cFound)
2263 {
2264 RTListForEach(&pThis->v.paValidPolicyDepthLists[iDepth], pCur, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2265 {
2266 if (RTAsn1ObjId_CompareWithString(pCur->pValidPolicy, RTCRX509_ID_CE_CP_ANY_POLICY_OID) == 0)
2267 {
2268 if (!rtCrX509CpvPolicyTreeInsertNew(pThis, pCur->pParent, iDepth,
2269 &pOne->IssuerDomainPolicy,
2270 pCur->pPolicyQualifiers,
2271 &pOne->SubjectDomainPolicy))
2272 return false;
2273 break;
2274 }
2275 }
2276 }
2277 }
2278 }
2279 else
2280 {
2281 /*
2282 * 6.1.4.b.2 - Remove matching policies from the tree if mapping is
2283 * inhibited and prune the tree.
2284 */
2285 uint32_t cRemoved = 0;
2286 i = pPolicyMappings->cItems;
2287 while (i-- > 0)
2288 {
2289 PCRTCRX509POLICYMAPPING const pOne = pPolicyMappings->papItems[i];
2290 RTListForEachSafe(&pThis->v.paValidPolicyDepthLists[iDepth], pCur, pNext, RTCRX509CERTPATHSPOLICYNODE, DepthEntry)
2291 {
2292 if (RTAsn1ObjId_Compare(pCur->pValidPolicy, &pOne->IssuerDomainPolicy))
2293 {
2294 rtCrX509CpvPolicyTreeDestroyNode(pThis, pCur);
2295 cRemoved++;
2296 }
2297 }
2298 }
2299 if (cRemoved)
2300 rtCrX509CpvPolicyTreePrune(pThis, iDepth - 1);
2301 }
2302
2303 return true;
2304}
2305
2306
2307/**
2308 * Step 6.1.4.d-f & 6.1.5.c-e.
2309 */
2310static void rtCrX509CpvSetWorkingPublicKeyInfo(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
2311{
2312 PCRTCRX509TBSCERTIFICATE const pTbsCert = &pNode->pCert->TbsCertificate;
2313
2314 /*
2315 * 6.1.4.d - The public key.
2316 */
2317 pThis->v.pWorkingPublicKey = &pTbsCert->SubjectPublicKeyInfo.SubjectPublicKey;
2318
2319 /*
2320 * 6.1.4.e - The public key parameters. Use new ones if present, keep old
2321 * if the algorithm remains the same.
2322 */
2323 if ( RTASN1CORE_IS_PRESENT(&pTbsCert->SubjectPublicKeyInfo.Algorithm.Parameters.u.Core)
2324 && pTbsCert->SubjectPublicKeyInfo.Algorithm.Parameters.enmType != RTASN1TYPE_NULL)
2325 pThis->v.pWorkingPublicKeyParameters = &pTbsCert->SubjectPublicKeyInfo.Algorithm.Parameters;
2326 else if ( pThis->v.pWorkingPublicKeyParameters
2327 && RTAsn1ObjId_Compare(pThis->v.pWorkingPublicKeyAlgorithm, &pTbsCert->SubjectPublicKeyInfo.Algorithm.Algorithm) != 0)
2328 pThis->v.pWorkingPublicKeyParameters = NULL;
2329
2330 /*
2331 * 6.1.4.f - The public algorithm.
2332 */
2333 pThis->v.pWorkingPublicKeyAlgorithm = &pTbsCert->SubjectPublicKeyInfo.Algorithm.Algorithm;
2334}
2335
2336
2337/**
2338 * Step 6.1.4.g.
2339 */
2340static bool rtCrX509CpvSoakUpNameConstraints(PRTCRX509CERTPATHSINT pThis, PCRTCRX509NAMECONSTRAINTS pNameConstraints)
2341{
2342 if (pNameConstraints->T0.PermittedSubtrees.cItems > 0)
2343 if (!rtCrX509CpvIntersectionPermittedSubtrees(pThis, &pNameConstraints->T0.PermittedSubtrees))
2344 return false;
2345
2346 if (pNameConstraints->T1.ExcludedSubtrees.cItems > 0)
2347 if (!rtCrX509CpvAddExcludedSubtrees(pThis, &pNameConstraints->T1.ExcludedSubtrees))
2348 return false;
2349
2350 return true;
2351}
2352
2353
2354/**
2355 * Step 6.1.4.i.
2356 */
2357static bool rtCrX509CpvSoakUpPolicyConstraints(PRTCRX509CERTPATHSINT pThis, PCRTCRX509POLICYCONSTRAINTS pPolicyConstraints)
2358{
2359 if (RTAsn1Integer_IsPresent(&pPolicyConstraints->RequireExplicitPolicy))
2360 {
2361 if (RTAsn1Integer_UnsignedCompareWithU32(&pPolicyConstraints->RequireExplicitPolicy, pThis->v.cExplicitPolicy) < 0)
2362 pThis->v.cExplicitPolicy = pPolicyConstraints->RequireExplicitPolicy.uValue.s.Lo;
2363 }
2364
2365 if (RTAsn1Integer_IsPresent(&pPolicyConstraints->InhibitPolicyMapping))
2366 {
2367 if (RTAsn1Integer_UnsignedCompareWithU32(&pPolicyConstraints->InhibitPolicyMapping, pThis->v.cInhibitPolicyMapping) < 0)
2368 pThis->v.cInhibitPolicyMapping = pPolicyConstraints->InhibitPolicyMapping.uValue.s.Lo;
2369 }
2370 return true;
2371}
2372
2373
2374/**
2375 * Step 6.1.4.j.
2376 */
2377static bool rtCrX509CpvSoakUpInhibitAnyPolicy(PRTCRX509CERTPATHSINT pThis, PCRTASN1INTEGER pInhibitAnyPolicy)
2378{
2379 if (RTAsn1Integer_UnsignedCompareWithU32(pInhibitAnyPolicy, pThis->v.cInhibitAnyPolicy) < 0)
2380 pThis->v.cInhibitAnyPolicy = pInhibitAnyPolicy->uValue.s.Lo;
2381 return true;
2382}
2383
2384
2385/**
2386 * Steps 6.1.4.k, 6.1.4.l, 6.1.4.m, and 6.1.4.n.
2387 */
2388static bool rtCrX509CpvCheckAndSoakUpBasicConstraintsAndKeyUsage(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode,
2389 bool fSelfIssued)
2390{
2391 /* 6.1.4.k - If basic constraints present, CA must be set. */
2392 if (RTAsn1Integer_UnsignedCompareWithU32(&pNode->pCert->TbsCertificate.T0.Version, RTCRX509TBSCERTIFICATE_V3) != 0)
2393 {
2394 /* Note! Add flags if support for older certificates is needed later. */
2395 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NOT_V3_CERT,
2396 "Only version 3 certificates are supported (Version=%llu)",
2397 pNode->pCert->TbsCertificate.T0.Version.uValue);
2398 }
2399 PCRTCRX509BASICCONSTRAINTS pBasicConstraints = pNode->pCert->TbsCertificate.T3.pBasicConstraints;
2400 if (pBasicConstraints)
2401 {
2402 if (!pBasicConstraints->CA.fValue)
2403 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NOT_CA_CERT,
2404 "Intermediate certificate (#%u) is not marked as a CA", pThis->v.iNode);
2405 }
2406
2407 /* 6.1.4.l - Work cMaxPathLength. */
2408 if (!fSelfIssued)
2409 {
2410 if (pThis->v.cMaxPathLength > 0)
2411 pThis->v.cMaxPathLength--;
2412 else
2413 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_MAX_PATH_LENGTH,
2414 "Hit max path length at node #%u", pThis->v.iNode);
2415 }
2416
2417 /* 6.1.4.m - Update cMaxPathLength if basic constrain field is present and smaller. */
2418 if (pBasicConstraints)
2419 {
2420 if (RTAsn1Integer_IsPresent(&pBasicConstraints->PathLenConstraint))
2421 if (RTAsn1Integer_UnsignedCompareWithU32(&pBasicConstraints->PathLenConstraint, pThis->v.cMaxPathLength) < 0)
2422 pThis->v.cMaxPathLength = pBasicConstraints->PathLenConstraint.uValue.s.Lo;
2423 }
2424
2425 /* 6.1.4.n - Require keyCertSign in key usage if the extension is present. */
2426 PCRTCRX509TBSCERTIFICATE const pTbsCert = &pNode->pCert->TbsCertificate;
2427 if ( (pTbsCert->T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE)
2428 && !(pTbsCert->T3.fKeyUsage & RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN))
2429 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_MISSING_KEY_CERT_SIGN,
2430 "Node #%u does not have KeyCertSign set (keyUsage=%#x)",
2431 pThis->v.iNode, pTbsCert->T3.fKeyUsage);
2432
2433 return true;
2434}
2435
2436
2437/**
2438 * Step 6.1.4.o - check out critical extensions.
2439 */
2440static bool rtCrX509CpvCheckCriticalExtensions(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
2441{
2442 uint32_t cLeft = pNode->pCert->TbsCertificate.T3.Extensions.cItems;
2443 PRTCRX509EXTENSION const *ppCur = pNode->pCert->TbsCertificate.T3.Extensions.papItems;
2444 while (cLeft-- > 0)
2445 {
2446 PCRTCRX509EXTENSION const pCur = *ppCur;
2447 if (pCur->Critical.fValue)
2448 {
2449 if ( RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_KEY_USAGE_OID) != 0
2450 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID) != 0
2451 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_ISSUER_ALT_NAME_OID) != 0
2452 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_BASIC_CONSTRAINTS_OID) != 0
2453 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_NAME_CONSTRAINTS_OID) != 0
2454 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_CERTIFICATE_POLICIES_OID) != 0
2455 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_POLICY_MAPPINGS_OID) != 0
2456 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_POLICY_CONSTRAINTS_OID) != 0
2457 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_EXT_KEY_USAGE_OID) != 0
2458 && RTAsn1ObjId_CompareWithString(&pCur->ExtnId, RTCRX509_ID_CE_INHIBIT_ANY_POLICY_OID) != 0
2459 )
2460 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_UNKNOWN_CRITICAL_EXTENSION,
2461 "Node #%u has an unknown critical extension: %s", pThis->v.iNode, pCur->ExtnId.szObjId);
2462 }
2463
2464 ppCur++;
2465 }
2466
2467 return true;
2468}
2469
2470
2471/**
2472 * Step 6.1.5 - The wrapping up.
2473 */
2474static bool rtCrX509CpvWrapUp(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pNode)
2475{
2476 Assert(!pNode->pParent); Assert(pThis->pTarget == pNode->pCert);
2477
2478 /*
2479 * 6.1.5.a - Decrement explicit policy.
2480 */
2481 if (pThis->v.cExplicitPolicy > 0)
2482 pThis->v.cExplicitPolicy--;
2483
2484 /*
2485 * 6.1.5.b - Policy constraints and explicit policy.
2486 */
2487 PCRTCRX509POLICYCONSTRAINTS pPolicyConstraints = pNode->pCert->TbsCertificate.T3.pPolicyConstraints;
2488 if ( pPolicyConstraints
2489 && RTAsn1Integer_IsPresent(&pPolicyConstraints->RequireExplicitPolicy)
2490 && RTAsn1Integer_UnsignedCompareWithU32(&pPolicyConstraints->RequireExplicitPolicy, 0) == 0)
2491 pThis->v.cExplicitPolicy = 0;
2492
2493 /*
2494 * 6.1.5.c-e - Update working public key info.
2495 */
2496 rtCrX509CpvSetWorkingPublicKeyInfo(pThis, pNode);
2497
2498 /*
2499 * 6.1.5.f - Critical extensions.
2500 */
2501 if (!rtCrX509CpvCheckCriticalExtensions(pThis, pNode))
2502 return false;
2503
2504 /*
2505 * 6.1.5.g - Calculate the intersection between the user initial policy set
2506 * and the valid policy tree.
2507 */
2508 rtCrX509CpvPolicyTreeIntersect(pThis, pThis->cInitialUserPolicySet, pThis->papInitialUserPolicySet);
2509
2510 if ( pThis->v.cExplicitPolicy == 0
2511 && pThis->v.pValidPolicyTree == NULL)
2512 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CPV_NO_VALID_POLICY, "No valid policy (wrap-up).");
2513
2514 return true;
2515}
2516
2517
2518/**
2519 * Worker that validates one path.
2520 *
2521 * This implements the algorithm in RFC-5280, section 6.1, with exception of
2522 * the CRL checks in 6.1.3.a.3.
2523 *
2524 * @returns success indicator.
2525 * @param pThis The path builder & validator instance.
2526 * @param pTrustAnchor The trust anchor node.
2527 */
2528static bool rtCrX509CpvOneWorker(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE pTrustAnchor)
2529{
2530 /*
2531 * Special case, target certificate is trusted.
2532 */
2533 if (!pTrustAnchor->pParent)
2534 return rtCrX509CpvFailed(pThis, VERR_CR_X509_CERTPATHS_INTERNAL_ERROR, "Target certificate is trusted.");
2535
2536 /*
2537 * Normal processing.
2538 */
2539 rtCrX509CpvInit(pThis, pTrustAnchor);
2540 if (RT_SUCCESS(pThis->rc))
2541 {
2542 PRTCRX509CERTPATHNODE pNode = pTrustAnchor->pParent;
2543 uint32_t iNode = pThis->v.iNode = 1; /* We count to cNode (inclusive). Same a validation tree depth. */
2544 while (pNode && RT_SUCCESS(pThis->rc))
2545 {
2546 /*
2547 * Basic certificate processing.
2548 */
2549 if (!rtCrX509CpvCheckBasicCertInfo(pThis, pNode)) /* Step 6.1.3.a */
2550 break;
2551
2552 bool const fSelfIssued = rtCrX509CertPathsIsSelfIssued(pNode);
2553 if (!fSelfIssued || !pNode->pParent) /* Step 6.1.3.b-c */
2554 if (!rtCrX509CpvCheckNameConstraints(pThis, pNode))
2555 break;
2556
2557 if (!rtCrX509CpvWorkValidPolicyTree(pThis, iNode, pNode, fSelfIssued)) /* Step 6.1.3.d-f */
2558 break;
2559
2560 /*
2561 * If it's the last certificate in the path, do wrap-ups.
2562 */
2563 if (!pNode->pParent) /* Step 6.1.5 */
2564 {
2565 Assert(iNode == pThis->v.cNodes);
2566 if (!rtCrX509CpvWrapUp(pThis, pNode))
2567 break;
2568 AssertRCBreak(pThis->rc);
2569 return true;
2570 }
2571
2572 /*
2573 * Preparations for the next certificate.
2574 */
2575 PCRTCRX509TBSCERTIFICATE const pTbsCert = &pNode->pCert->TbsCertificate;
2576 if ( pTbsCert->T3.pPolicyMappings
2577 && !rtCrX509CpvSoakUpPolicyMappings(pThis, iNode, pTbsCert->T3.pPolicyMappings)) /* Step 6.1.4.a-b */
2578 break;
2579
2580 pThis->v.pWorkingIssuer = &pTbsCert->Subject; /* Step 6.1.4.c */
2581
2582 rtCrX509CpvSetWorkingPublicKeyInfo(pThis, pNode); /* Step 6.1.4.d-f */
2583
2584 if ( pTbsCert->T3.pNameConstraints /* Step 6.1.4.g */
2585 && !rtCrX509CpvSoakUpNameConstraints(pThis, pTbsCert->T3.pNameConstraints))
2586 break;
2587
2588 if (!fSelfIssued) /* Step 6.1.4.h */
2589 {
2590 if (pThis->v.cExplicitPolicy > 0)
2591 pThis->v.cExplicitPolicy--;
2592 if (pThis->v.cInhibitPolicyMapping > 0)
2593 pThis->v.cInhibitPolicyMapping--;
2594 if (pThis->v.cInhibitAnyPolicy > 0)
2595 pThis->v.cInhibitAnyPolicy--;
2596 }
2597
2598 if ( pTbsCert->T3.pPolicyConstraints /* Step 6.1.4.j */
2599 && !rtCrX509CpvSoakUpPolicyConstraints(pThis, pTbsCert->T3.pPolicyConstraints))
2600 break;
2601
2602 if ( pTbsCert->T3.pInhibitAnyPolicy /* Step 6.1.4.j */
2603 && !rtCrX509CpvSoakUpInhibitAnyPolicy(pThis, pTbsCert->T3.pInhibitAnyPolicy))
2604 break;
2605
2606 if (!rtCrX509CpvCheckAndSoakUpBasicConstraintsAndKeyUsage(pThis, pNode, fSelfIssued)) /* Step 6.1.4.k-n */
2607 break;
2608
2609 if (!rtCrX509CpvCheckCriticalExtensions(pThis, pNode)) /* Step 6.1.4.o */
2610 break;
2611
2612 /*
2613 * Advance to the next certificate.
2614 */
2615 pNode = pNode->pParent;
2616 pThis->v.iNode = ++iNode;
2617 }
2618 AssertStmt(RT_FAILURE_NP(pThis->rc), pThis->rc = VERR_CR_X509_CERTPATHS_INTERNAL_ERROR);
2619 }
2620 return false;
2621}
2622
2623
2624RTDECL(int) RTCrX509CertPathsValidateOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, PRTERRINFO pErrInfo)
2625{
2626 /*
2627 * Validate the input.
2628 */
2629 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2630 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2631 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
2632 AssertReturn(!(pThis->fFlags & ~RTCRX509CERTPATHSINT_F_VALID_MASK), VERR_INVALID_PARAMETER);
2633 AssertPtrReturn(pThis->pTarget, VERR_INVALID_PARAMETER);
2634 AssertPtrReturn(pThis->pRoot, VERR_INVALID_PARAMETER);
2635 AssertReturn(pThis->rc == VINF_SUCCESS, VERR_INVALID_PARAMETER);
2636
2637 /*
2638 * Locate the path and validate it.
2639 */
2640 int rc;
2641 if (iPath < pThis->cPaths)
2642 {
2643 PRTCRX509CERTPATHNODE pLeaf = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
2644 if (pLeaf)
2645 {
2646 if (RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(pLeaf->uSrc))
2647 {
2648 pThis->pErrInfo = pErrInfo;
2649 rtCrX509CpvOneWorker(pThis, pLeaf);
2650 pThis->pErrInfo = NULL;
2651 rc = pThis->rc;
2652 pThis->rc = VINF_SUCCESS;
2653 }
2654 else
2655 rc = RTErrInfoSetF(pErrInfo, VERR_CR_X509_NO_TRUST_ANCHOR, "Path #%u is does not have a trust anchor: uSrc=%s",
2656 iPath, rtCrX509CertPathsNodeGetSourceName(pLeaf));
2657 pLeaf->rcVerify = rc;
2658 }
2659 else
2660 rc = VERR_CR_X509_CERTPATHS_INTERNAL_ERROR;
2661 }
2662 else
2663 rc = VERR_NOT_FOUND;
2664 return rc;
2665}
2666
2667
2668RTDECL(int) RTCrX509CertPathsValidateAll(RTCRX509CERTPATHS hCertPaths, uint32_t *pcValidPaths, PRTERRINFO pErrInfo)
2669{
2670 /*
2671 * Validate the input.
2672 */
2673 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2674 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2675 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
2676 AssertReturn(!(pThis->fFlags & ~RTCRX509CERTPATHSINT_F_VALID_MASK), VERR_INVALID_PARAMETER);
2677 AssertPtrReturn(pThis->pTarget, VERR_INVALID_PARAMETER);
2678 AssertPtrReturn(pThis->pRoot, VERR_INVALID_PARAMETER);
2679 AssertReturn(pThis->rc == VINF_SUCCESS, VERR_INVALID_PARAMETER);
2680 AssertPtrNullReturn(pcValidPaths, VERR_INVALID_POINTER);
2681
2682 /*
2683 * Validate the paths.
2684 */
2685 pThis->pErrInfo = pErrInfo;
2686
2687 int rcLastFailure = VINF_SUCCESS;
2688 uint32_t cValidPaths = 0;
2689 PRTCRX509CERTPATHNODE pCurLeaf;
2690 RTListForEach(&pThis->LeafList, pCurLeaf, RTCRX509CERTPATHNODE, ChildListOrLeafEntry)
2691 {
2692 if (RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(pCurLeaf->uSrc))
2693 {
2694 rtCrX509CpvOneWorker(hCertPaths, pCurLeaf);
2695 if (RT_SUCCESS(pThis->rc))
2696 cValidPaths++;
2697 else
2698 rcLastFailure = pThis->rc;
2699 pCurLeaf->rcVerify = pThis->rc;
2700 pThis->rc = VINF_SUCCESS;
2701 }
2702 else
2703 pCurLeaf->rcVerify = VERR_CR_X509_NO_TRUST_ANCHOR;
2704 }
2705
2706 pThis->pErrInfo = NULL;
2707
2708 if (pcValidPaths)
2709 *pcValidPaths = cValidPaths;
2710 if (cValidPaths > 0)
2711 return VINF_SUCCESS;
2712 if (RT_SUCCESS_NP(rcLastFailure))
2713 return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CPV_NO_TRUSTED_PATHS,
2714 "None of the %u path(s) have a trust anchor.", pThis->cPaths);
2715 return rcLastFailure;
2716}
2717
2718
2719RTDECL(uint32_t) RTCrX509CertPathsGetPathCount(RTCRX509CERTPATHS hCertPaths)
2720{
2721 /*
2722 * Validate the input.
2723 */
2724 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2725 AssertPtrReturn(pThis, UINT32_MAX);
2726 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, UINT32_MAX);
2727 AssertPtrReturn(pThis->pRoot, UINT32_MAX);
2728
2729 /*
2730 * Return data.
2731 */
2732 return pThis->cPaths;
2733}
2734
2735
2736RTDECL(int) RTCrX509CertPathsQueryPathInfo(RTCRX509CERTPATHS hCertPaths, uint32_t iPath,
2737 bool *pfTrusted, uint32_t *pcNodes, PCRTCRX509NAME *ppSubject,
2738 PCRTCRX509SUBJECTPUBLICKEYINFO *ppPublicKeyInfo,
2739 PCRTCRX509CERTIFICATE *ppCert, PCRTCRCERTCTX *ppCertCtx,
2740 int *prcVerify)
2741{
2742 /*
2743 * Validate the input.
2744 */
2745 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2746 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2747 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
2748 AssertPtrReturn(pThis->pRoot, VERR_WRONG_ORDER);
2749 AssertReturn(iPath < pThis->cPaths, VERR_NOT_FOUND);
2750
2751 /*
2752 * Get the data.
2753 */
2754 PRTCRX509CERTPATHNODE pLeaf = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
2755 AssertReturn(pLeaf, VERR_CR_X509_INTERNAL_ERROR);
2756
2757 if (pfTrusted)
2758 *pfTrusted = RTCRX509CERTPATHNODE_SRC_IS_TRUSTED(pLeaf->uSrc);
2759
2760 if (pcNodes)
2761 *pcNodes = pLeaf->uDepth + 1; /* Includes both trust anchor and target. */
2762
2763 if (ppSubject)
2764 *ppSubject = pLeaf->pCert ? &pLeaf->pCert->TbsCertificate.Subject : &pLeaf->pCertCtx->pTaInfo->CertPath.TaName;
2765
2766 if (ppPublicKeyInfo)
2767 *ppPublicKeyInfo = pLeaf->pCert ? &pLeaf->pCert->TbsCertificate.SubjectPublicKeyInfo : &pLeaf->pCertCtx->pTaInfo->PubKey;
2768
2769 if (ppCert)
2770 *ppCert = pLeaf->pCert;
2771
2772 if (ppCertCtx)
2773 {
2774 if (pLeaf->pCertCtx)
2775 {
2776 uint32_t cRefs = RTCrCertCtxRetain(pLeaf->pCertCtx);
2777 AssertReturn(cRefs != UINT32_MAX, VERR_CR_X509_INTERNAL_ERROR);
2778 }
2779 *ppCertCtx = pLeaf->pCertCtx;
2780 }
2781
2782 if (prcVerify)
2783 *prcVerify = pLeaf->rcVerify;
2784
2785 return VINF_SUCCESS;
2786}
2787
2788
2789RTDECL(uint32_t) RTCrX509CertPathsGetPathLength(RTCRX509CERTPATHS hCertPaths, uint32_t iPath)
2790{
2791 /*
2792 * Validate the input.
2793 */
2794 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2795 AssertPtrReturn(pThis, UINT32_MAX);
2796 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, UINT32_MAX);
2797 AssertPtrReturn(pThis->pRoot, UINT32_MAX);
2798 AssertReturn(iPath < pThis->cPaths, UINT32_MAX);
2799
2800 /*
2801 * Get the data.
2802 */
2803 PRTCRX509CERTPATHNODE pLeaf = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
2804 AssertReturn(pLeaf, UINT32_MAX);
2805 return pLeaf->uDepth + 1;
2806}
2807
2808
2809RTDECL(int) RTCrX509CertPathsGetPathVerifyResult(RTCRX509CERTPATHS hCertPaths, uint32_t iPath)
2810{
2811 /*
2812 * Validate the input.
2813 */
2814 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2815 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2816 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, VERR_INVALID_HANDLE);
2817 AssertPtrReturn(pThis->pRoot, VERR_WRONG_ORDER);
2818 AssertReturn(iPath < pThis->cPaths, VERR_NOT_FOUND);
2819
2820 /*
2821 * Get the data.
2822 */
2823 PRTCRX509CERTPATHNODE pLeaf = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
2824 AssertReturn(pLeaf, VERR_CR_X509_INTERNAL_ERROR);
2825
2826 return pLeaf->rcVerify;
2827}
2828
2829
2830static PRTCRX509CERTPATHNODE rtCrX509CertPathsGetPathNodeByIndexes(PRTCRX509CERTPATHSINT pThis, uint32_t iPath, uint32_t iNode)
2831{
2832 PRTCRX509CERTPATHNODE pNode = rtCrX509CertPathsGetLeafByIndex(pThis, iPath);
2833 Assert(pNode);
2834 if (pNode)
2835 {
2836 if (iNode <= pNode->uDepth)
2837 {
2838 uint32_t uCertDepth = pNode->uDepth - iNode;
2839 while (pNode->uDepth > uCertDepth)
2840 pNode = pNode->pParent;
2841 Assert(pNode);
2842 Assert(pNode && pNode->uDepth == uCertDepth);
2843 return pNode;
2844 }
2845 }
2846
2847 return NULL;
2848}
2849
2850
2851RTDECL(PCRTCRX509CERTIFICATE) RTCrX509CertPathsGetPathNodeCert(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t iNode)
2852{
2853 /*
2854 * Validate the input.
2855 */
2856 PRTCRX509CERTPATHSINT pThis = hCertPaths;
2857 AssertPtrReturn(pThis, NULL);
2858 AssertReturn(pThis->u32Magic == RTCRX509CERTPATHSINT_MAGIC, NULL);
2859 AssertPtrReturn(pThis->pRoot, NULL);
2860 AssertReturn(iPath < pThis->cPaths, NULL);
2861
2862 /*
2863 * Get the data.
2864 */
2865 PRTCRX509CERTPATHNODE pNode = rtCrX509CertPathsGetPathNodeByIndexes(pThis, iPath, iNode);
2866 if (pNode)
2867 return pNode->pCert;
2868 return NULL;
2869}
2870
2871
2872/** @} */
2873
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