VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/x509-core.cpp@ 64883

最後變更 在這個檔案從64883是 64883,由 vboxsync 提交於 8 年 前

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).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 58.7 KB
 
1/* $Id: x509-core.cpp 64883 2016-12-15 15:26:20Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - X.509, Core APIs.
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.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/crypto/x509.h>
33
34#include <iprt/err.h>
35#include <iprt/string.h>
36#include <iprt/uni.h>
37
38#include "x509-internal.h"
39
40
41/*
42 * Generate the code.
43 */
44#include <iprt/asn1-generator-core.h>
45
46
47/*
48 * X.509 Validity.
49 */
50
51RTDECL(bool) RTCrX509Validity_IsValidAtTimeSpec(PCRTCRX509VALIDITY pThis, PCRTTIMESPEC pTimeSpec)
52{
53 if (RTAsn1Time_CompareWithTimeSpec(&pThis->NotBefore, pTimeSpec) > 0)
54 return false;
55 if (RTAsn1Time_CompareWithTimeSpec(&pThis->NotAfter, pTimeSpec) < 0)
56 return false;
57 return true;
58}
59
60
61/*
62 * One X.509 Algorithm Identifier.
63 */
64
65RTDECL(RTDIGESTTYPE) RTCrX509AlgorithmIdentifier_QueryDigestType(PCRTCRX509ALGORITHMIDENTIFIER pThis)
66{
67 AssertPtrReturn(pThis, RTDIGESTTYPE_INVALID);
68 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_MD5))
69 return RTDIGESTTYPE_MD5;
70 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA1))
71 return RTDIGESTTYPE_SHA1;
72 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA256))
73 return RTDIGESTTYPE_SHA256;
74 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512))
75 return RTDIGESTTYPE_SHA512;
76
77 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA384))
78 return RTDIGESTTYPE_SHA384;
79 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA224))
80 return RTDIGESTTYPE_SHA224;
81 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512T224))
82 return RTDIGESTTYPE_SHA512T224;
83 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512T256))
84 return RTDIGESTTYPE_SHA512T256;
85 return RTDIGESTTYPE_INVALID;
86}
87
88
89RTDECL(uint32_t) RTCrX509AlgorithmIdentifier_QueryDigestSize(PCRTCRX509ALGORITHMIDENTIFIER pThis)
90{
91 AssertPtrReturn(pThis, UINT32_MAX);
92
93 /* common */
94 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_MD5))
95 return 128 / 8;
96 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA1))
97 return 160 / 8;
98 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA256))
99 return 256 / 8;
100 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512))
101 return 512 / 8;
102
103 /* Less common. */
104 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_MD2))
105 return 128 / 8;
106 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_MD4))
107 return 128 / 8;
108 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA384))
109 return 384 / 8;
110 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA224))
111 return 224 / 8;
112 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512T224))
113 return 224 / 8;
114 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_SHA512T256))
115 return 256 / 8;
116 if (!strcmp(pThis->Algorithm.szObjId, RTCRX509ALGORITHMIDENTIFIERID_WHIRLPOOL))
117 return 512 / 8;
118
119 return UINT32_MAX;
120}
121
122
123RTDECL(int) RTCrX509AlgorithmIdentifier_CompareWithString(PCRTCRX509ALGORITHMIDENTIFIER pThis, const char *pszObjId)
124{
125 return strcmp(pThis->Algorithm.szObjId, pszObjId);
126}
127
128
129RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid(const char *pszDigestOid,
130 const char *pszEncryptedDigestOid)
131{
132 /* common */
133 if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD5))
134 {
135 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA))
136 return 0;
137 }
138 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA1))
139 {
140 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA))
141 return 0;
142 }
143 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA256))
144 {
145 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA))
146 return 0;
147 }
148 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA512))
149 {
150 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA))
151 return 0;
152 }
153 /* Less common. */
154 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD2))
155 {
156 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA))
157 return 0;
158 }
159 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD4))
160 {
161 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA))
162 return 0;
163 }
164 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA384))
165 {
166 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA))
167 return 0;
168 }
169 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA224))
170 {
171 if (!strcmp(pszEncryptedDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA))
172 return 0;
173 }
174 else if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_WHIRLPOOL))
175 {
176 /* ?? */
177 }
178 else
179 return -1;
180 return 1;
181}
182
183RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest(PCRTCRX509ALGORITHMIDENTIFIER pDigest,
184 PCRTCRX509ALGORITHMIDENTIFIER pEncryptedDigest)
185{
186 return RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid(pDigest->Algorithm.szObjId,
187 pEncryptedDigest->Algorithm.szObjId);
188}
189
190
191RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(const char *pszEncryptionOid,
192 const char *pszDigestOid)
193{
194 /* RSA: */
195 if (!strcmp(pszEncryptionOid, RTCRX509ALGORITHMIDENTIFIERID_RSA))
196 {
197 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD5)
198 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA))
199 return RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA;
200 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA1)
201 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA))
202 return RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA;
203 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA256)
204 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA))
205 return RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA;
206 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA512)
207 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA))
208 return RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA;
209 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD2)
210 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA))
211 return RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA;
212 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD4)
213 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA))
214 return RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA;
215 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA384)
216 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA))
217 return RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA;
218 if ( !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA224)
219 || !strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA))
220 return RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA;
221
222 /* if (!strcmp(pszDigestOid, RTCRX509ALGORITHMIDENTIFIERID_WHIRLPOOL))
223 return ???; */
224 }
225 else if (RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid(pszDigestOid, pszEncryptionOid) == 0)
226 return pszEncryptionOid;
227
228 AssertMsgFailed(("enc=%s hash=%s\n", pszEncryptionOid, pszDigestOid));
229 return NULL;
230}
231
232
233RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest(PCRTCRX509ALGORITHMIDENTIFIER pEncryption,
234 PCRTCRX509ALGORITHMIDENTIFIER pDigest)
235{
236 return RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(pEncryption->Algorithm.szObjId,
237 pDigest->Algorithm.szObjId);
238}
239
240
241/*
242 * Set of X.509 Algorithm Identifiers.
243 */
244
245
246/*
247 * One X.509 AttributeTypeAndValue.
248 */
249
250
251/*
252 * Set of X.509 AttributeTypeAndValues / X.509 RelativeDistinguishedName.
253 */
254
255/**
256 * Slow code path of rtCrX509CanNameIsNothing.
257 *
258 * @returns true if @uc maps to nothing, false if not.
259 * @param uc The unicode code point.
260 */
261static bool rtCrX509CanNameIsNothingSlow(RTUNICP uc)
262{
263 switch (uc)
264 {
265 /* 2.2 Map - Paragraph 1: */
266 case 0x00ad:
267 case 0x1806:
268 case 0x034f:
269 case 0x180b: case 0x180c: case 0x180d:
270
271 case 0xfe00: case 0xfe01: case 0xfe02: case 0xfe03:
272 case 0xfe04: case 0xfe05: case 0xfe06: case 0xfe07:
273 case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b:
274 case 0xfe0c: case 0xfe0d: case 0xfe0e: case 0xfe0f:
275
276 case 0xfffc:
277
278 /* 2.2 Map - Paragraph 3 (control code/function): */
279 case 0x0000: case 0x0001: case 0x0002: case 0x0003:
280 case 0x0004: case 0x0005: case 0x0006: case 0x0007:
281 case 0x0008:
282
283 case 0x000e: case 0x000f:
284 case 0x0010: case 0x0011: case 0x0012: case 0x0013:
285 case 0x0014: case 0x0015: case 0x0016: case 0x0017:
286 case 0x0018: case 0x0019: case 0x001a: case 0x001b:
287 case 0x001c: case 0x001d: case 0x001e: case 0x001f:
288
289 case 0x007f:
290 case 0x0080: case 0x0081: case 0x0082: case 0x0083:
291 case 0x0084: /*case 0x0085:*/ case 0x0086: case 0x0087:
292 case 0x0088: case 0x0089: case 0x008a: case 0x008b:
293 case 0x008c: case 0x008d: case 0x008e: case 0x008f:
294 case 0x0090: case 0x0091: case 0x0092: case 0x0093:
295 case 0x0094: case 0x0095: case 0x0096: case 0x0097:
296 case 0x0098: case 0x0099: case 0x009a: case 0x009b:
297 case 0x009c: case 0x009d: case 0x009e: case 0x009f:
298
299 case 0x06dd:
300 case 0x070f:
301 case 0x180e:
302 case 0x200c: case 0x200d: case 0x200e: case 0x200f:
303 case 0x202a: case 0x202b: case 0x202c: case 0x202d: case 0x202e:
304 case 0x2060: case 0x2061: case 0x2062: case 0x2063:
305 case 0x206a: case 0x206b: case 0x206c: case 0x206d: case 0x206e: case 0x206f:
306 case 0xfeff:
307 case 0xfff9: case 0xfffa: case 0xfffb:
308 case 0x1d173: case 0x1d174: case 0x1d175: case 0x1d176: case 0x1d177: case 0x1d178: case 0x1d179: case 0x1d17a:
309 case 0xe0001:
310 case 0xe0020: case 0xe0021: case 0xe0022: case 0xe0023:
311 case 0xe0024: case 0xe0025: case 0xe0026: case 0xe0027:
312 case 0xe0028: case 0xe0029: case 0xe002a: case 0xe002b:
313 case 0xe002c: case 0xe002d: case 0xe002e: case 0xe002f:
314 case 0xe0030: case 0xe0031: case 0xe0032: case 0xe0033:
315 case 0xe0034: case 0xe0035: case 0xe0036: case 0xe0037:
316 case 0xe0038: case 0xe0039: case 0xe003a: case 0xe003b:
317 case 0xe003c: case 0xe003d: case 0xe003e: case 0xe003f:
318 case 0xe0040: case 0xe0041: case 0xe0042: case 0xe0043:
319 case 0xe0044: case 0xe0045: case 0xe0046: case 0xe0047:
320 case 0xe0048: case 0xe0049: case 0xe004a: case 0xe004b:
321 case 0xe004c: case 0xe004d: case 0xe004e: case 0xe004f:
322 case 0xe0050: case 0xe0051: case 0xe0052: case 0xe0053:
323 case 0xe0054: case 0xe0055: case 0xe0056: case 0xe0057:
324 case 0xe0058: case 0xe0059: case 0xe005a: case 0xe005b:
325 case 0xe005c: case 0xe005d: case 0xe005e: case 0xe005f:
326 case 0xe0060: case 0xe0061: case 0xe0062: case 0xe0063:
327 case 0xe0064: case 0xe0065: case 0xe0066: case 0xe0067:
328 case 0xe0068: case 0xe0069: case 0xe006a: case 0xe006b:
329 case 0xe006c: case 0xe006d: case 0xe006e: case 0xe006f:
330 case 0xe0070: case 0xe0071: case 0xe0072: case 0xe0073:
331 case 0xe0074: case 0xe0075: case 0xe0076: case 0xe0077:
332 case 0xe0078: case 0xe0079: case 0xe007a: case 0xe007b:
333 case 0xe007c: case 0xe007d: case 0xe007e: case 0xe007f:
334
335 /* 2.2 Map - Paragraph 4. */
336 case 0x200b:
337 return true;
338 }
339 return false;
340}
341
342
343/**
344 * Checks if @a uc maps to nothing according to mapping rules of RFC-5280 and
345 * RFC-4518.
346 *
347 * @returns true if @uc maps to nothing, false if not.
348 * @param uc The unicode code point.
349 */
350DECLINLINE(bool) rtCrX509CanNameIsNothing(RTUNICP uc)
351{
352 if (uc > 0x001f && uc < 0x00ad)
353 return false;
354 return rtCrX509CanNameIsNothingSlow(uc);
355}
356
357
358/**
359 * Slow code path of rtCrX509CanNameIsSpace.
360 *
361 * @returns true if space, false if not.
362 * @param uc The unicode code point.
363 */
364static bool rtCrX509CanNameIsSpaceSlow(RTUNICP uc)
365{
366 switch (uc)
367 {
368 /* 2.2 Map - Paragraph 2. */
369 case 0x09:
370 case 0x0a:
371 case 0x0b:
372 case 0x0c:
373 case 0x0d:
374 case 0x20:
375 case 0x0085:
376 case 0x00a0:
377 case 0x1680:
378 case 0x2000: case 0x2001: case 0x2002: case 0x2003:
379 case 0x2004: case 0x2005: case 0x2006: case 0x2007:
380 case 0x2008: case 0x2009: case 0x200a:
381 case 0x2028: case 0x2029:
382 case 0x202f:
383 case 0x205f:
384 case 0x3000:
385 return true;
386 }
387 return false;
388}
389
390
391/**
392 * Checks if @a uc is a space character according to the mapping rules of
393 * RFC-5280 and RFC-4518.
394 *
395 * @returns true if space, false if not.
396 * @param uc The unicode code point.
397 */
398DECLINLINE(bool) rtCrX509CanNameIsSpace(RTUNICP uc)
399{
400 if (uc < 0x0085)
401 {
402 if (uc > 0x0020)
403 return false;
404 if (uc == 0x0020) /* space */
405 return true;
406 }
407 return rtCrX509CanNameIsSpaceSlow(uc);
408}
409
410
411static const char *rtCrX509CanNameStripLeft(const char *psz, size_t *pcch)
412{
413 /*
414 * Return space when we've encountered the first non-space-non-nothing code point.
415 */
416 const char * const pszStart = psz;
417 const char *pszPrev;
418 for (;;)
419 {
420 pszPrev = psz;
421 RTUNICP uc;
422 int rc = RTStrGetCpEx(&psz, &uc);
423 AssertRCBreak(rc);
424 if (!uc)
425 {
426 if ((uintptr_t)(pszPrev - pszStart) >= *pcch)
427 break;
428 /* NUL inside the string, maps to nothing => ignore it. */
429 }
430 else if (!rtCrX509CanNameIsSpace(uc) && !rtCrX509CanNameIsNothing(uc))
431 break;
432 }
433 *pcch -= pszPrev - pszStart;
434 return pszPrev;
435}
436
437
438static RTUNICP rtCrX509CanNameGetNextCpWithMappingSlowSpace(const char **ppsz, size_t *pcch)
439{
440 /*
441 * Return space when we've encountered the first non-space-non-nothing code point.
442 */
443 RTUNICP uc;
444 const char *psz = *ppsz;
445 const char * const pszStart = psz;
446 const char *pszPrev;
447 for (;;)
448 {
449 pszPrev = psz;
450 int rc = RTStrGetCpEx(&psz, &uc);
451 AssertRCBreakStmt(rc, uc = 0x20);
452 if (!uc)
453 {
454 if ((uintptr_t)(pszPrev - pszStart) >= *pcch)
455 {
456 uc = 0; /* End of string: Ignore trailing spaces. */
457 break;
458 }
459 /* NUL inside the string, maps to nothing => ignore it. */
460 }
461 else if (!rtCrX509CanNameIsSpace(uc) && !rtCrX509CanNameIsNothing(uc))
462 {
463 uc = 0x20; /* Return space before current char. */
464 break;
465 }
466 }
467
468 *ppsz = pszPrev;
469 *pcch -= pszPrev - pszStart;
470 return uc;
471}
472
473
474DECLINLINE(RTUNICP) rtCrX509CanNameGetNextCpIgnoreNul(const char **ppsz, size_t *pcch)
475{
476 while (*pcch > 0)
477 {
478 const char *psz = *ppsz;
479 RTUNICP uc = *psz;
480 if (uc < 0x80)
481 {
482 *pcch -= 1;
483 *ppsz = psz + 1;
484 }
485 else
486 {
487 int rc = RTStrGetCpEx(ppsz, &uc);
488 AssertRCReturn(rc, uc);
489 size_t cchCp = *ppsz - psz;
490 AssertReturn(cchCp <= *pcch, 0);
491 *pcch -= cchCp;
492 }
493 if (uc != 0)
494 return uc;
495 }
496 return 0;
497}
498
499
500static RTUNICP rtCrX509CanNameGetNextCpWithMappingSlowNothing(const char **ppsz, size_t *pcch)
501{
502 /*
503 * Return first code point which doesn't map to nothing. If we encounter
504 * a space, we defer to the mapping-after-space routine above.
505 */
506 for (;;)
507 {
508 RTUNICP uc = rtCrX509CanNameGetNextCpIgnoreNul(ppsz, pcch);
509 if (rtCrX509CanNameIsSpace(uc))
510 return rtCrX509CanNameGetNextCpWithMappingSlowSpace(ppsz, pcch);
511 if (!rtCrX509CanNameIsNothing(uc) || uc == 0)
512 return uc;
513 }
514}
515
516
517DECLINLINE(RTUNICP) rtCrX509CanNameGetNextCpWithMapping(const char **ppsz, size_t *pcch)
518{
519 RTUNICP uc = rtCrX509CanNameGetNextCpIgnoreNul(ppsz, pcch);
520 if (uc)
521 {
522 if (!rtCrX509CanNameIsSpace(uc))
523 {
524 if (!rtCrX509CanNameIsNothing(uc))
525 return uc;
526 return rtCrX509CanNameGetNextCpWithMappingSlowNothing(ppsz, pcch);
527 }
528 return rtCrX509CanNameGetNextCpWithMappingSlowSpace(ppsz, pcch);
529 }
530 return uc;
531}
532
533
534RTDECL(bool) RTCrX509AttributeTypeAndValue_MatchAsRdnByRfc5280(PCRTCRX509ATTRIBUTETYPEANDVALUE pLeft,
535 PCRTCRX509ATTRIBUTETYPEANDVALUE pRight)
536{
537 if (RTAsn1ObjId_Compare(&pLeft->Type, &pRight->Type) == 0)
538 {
539 /*
540 * Try for perfect match in case we get luck.
541 */
542#ifdef DEBUG_bird /* Want to test the complicated code path first */
543 if (pLeft->Value.enmType != RTASN1TYPE_STRING || pRight->Value.enmType != RTASN1TYPE_STRING)
544#endif
545 if (RTAsn1DynType_Compare(&pLeft->Value, &pRight->Value) == 0)
546 return true;
547
548 /*
549 * If both are string types, we can compare them according to RFC-5280.
550 */
551 if ( pLeft->Value.enmType == RTASN1TYPE_STRING
552 && pRight->Value.enmType == RTASN1TYPE_STRING)
553 {
554 size_t cchLeft;
555 const char *pszLeft;
556 int rc = RTAsn1String_QueryUtf8(&pLeft->Value.u.String, &pszLeft, &cchLeft);
557 if (RT_SUCCESS(rc))
558 {
559 size_t cchRight;
560 const char *pszRight;
561 rc = RTAsn1String_QueryUtf8(&pRight->Value.u.String, &pszRight, &cchRight);
562 if (RT_SUCCESS(rc))
563 {
564 /*
565 * Perform a simplified RFC-5280 comparsion.
566 * The algorithm as be relaxed on the following counts:
567 * 1. No unicode normalization.
568 * 2. Prohibited characters not checked for.
569 * 3. Bidirectional characters are not ignored.
570 */
571 pszLeft = rtCrX509CanNameStripLeft(pszLeft, &cchLeft);
572 pszRight = rtCrX509CanNameStripLeft(pszRight, &cchRight);
573 while (*pszLeft && *pszRight)
574 {
575 RTUNICP ucLeft = rtCrX509CanNameGetNextCpWithMapping(&pszLeft, &cchLeft);
576 RTUNICP ucRight = rtCrX509CanNameGetNextCpWithMapping(&pszRight, &cchRight);
577 if (ucLeft != ucRight)
578 {
579 ucLeft = RTUniCpToLower(ucLeft);
580 ucRight = RTUniCpToLower(ucRight);
581 if (ucLeft != ucRight)
582 return false;
583 }
584 }
585
586 return cchRight == 0 && cchLeft == 0;
587 }
588 }
589 }
590 }
591 return false;
592}
593
594
595RTDECL(bool) RTCrX509RelativeDistinguishedName_MatchByRfc5280(PCRTCRX509RELATIVEDISTINGUISHEDNAME pLeft,
596 PCRTCRX509RELATIVEDISTINGUISHEDNAME pRight)
597{
598 /*
599 * No match if the attribute count differs.
600 */
601 uint32_t const cItems = pLeft->cItems;
602 if (cItems == pRight->cItems)
603 {
604 /*
605 * Compare each attribute, but don't insist on the same order nor
606 * bother checking for duplicates (too complicated).
607 */
608 for (uint32_t iLeft = 0; iLeft < cItems; iLeft++)
609 {
610 PCRTCRX509ATTRIBUTETYPEANDVALUE pLeftAttr = pLeft->papItems[iLeft];
611 bool fFound = false;
612 for (uint32_t iRight = 0; iRight < cItems; iRight++)
613 if (RTCrX509AttributeTypeAndValue_MatchAsRdnByRfc5280(pLeftAttr, pRight->papItems[iRight]))
614 {
615 fFound = true;
616 break;
617 }
618 if (!fFound)
619 return false;
620 }
621 return true;
622 }
623 return false;
624
625}
626
627
628/*
629 * X.509 Name.
630 */
631
632RTDECL(bool) RTCrX509Name_MatchByRfc5280(PCRTCRX509NAME pLeft, PCRTCRX509NAME pRight)
633{
634 uint32_t const cItems = pLeft->cItems;
635 if (cItems == pRight->cItems)
636 {
637 /* Require exact order. */
638 for (uint32_t iRdn = 0; iRdn < cItems; iRdn++)
639 if (!RTCrX509RelativeDistinguishedName_MatchByRfc5280(pLeft->papItems[iRdn], pRight->papItems[iRdn]))
640 return false;
641 return true;
642 }
643 return false;
644}
645
646
647RTDECL(bool) RTCrX509Name_ConstraintMatch(PCRTCRX509NAME pConstraint, PCRTCRX509NAME pName)
648{
649 /*
650 * Check that the constraint is a prefix of the name. This means that
651 * the name must have at least as many components and the constraint.
652 */
653 if (pName->cItems >= pConstraint->cItems)
654 {
655 /*
656 * Parallel crawl of the two RDNs arrays.
657 */
658 for (uint32_t i = 0; pConstraint->cItems; i++)
659 {
660 PCRTCRX509RELATIVEDISTINGUISHEDNAME pConstrRdns = pConstraint->papItems[i];
661 PCRTCRX509RELATIVEDISTINGUISHEDNAME pNameRdns = pName->papItems[i];
662
663 /*
664 * Walk the constraint attribute & value array.
665 */
666 for (uint32_t iConstrAttrib = 0; iConstrAttrib < pConstrRdns->cItems; iConstrAttrib++)
667 {
668 PCRTCRX509ATTRIBUTETYPEANDVALUE pConstrAttrib = pConstrRdns->papItems[iConstrAttrib];
669
670 /*
671 * Find matching attribute & value in the name.
672 */
673 bool fFound = false;
674 for (uint32_t iNameAttrib = 0; iNameAttrib < pNameRdns->cItems; iNameAttrib++)
675 if (RTCrX509AttributeTypeAndValue_MatchAsRdnByRfc5280(pConstrAttrib, pNameRdns->papItems[iNameAttrib]))
676 {
677 fFound = true;
678 break;
679 }
680 if (fFound)
681 return false;
682 }
683 }
684 return true;
685 }
686 return false;
687}
688
689
690/**
691 * Mapping between X.500 object IDs and short and long names.
692 *
693 * See RFC-1327, ...
694 */
695static struct
696{
697 const char *pszOid;
698 const char *pszShortNm;
699 size_t cchShortNm;
700 const char *pszLongNm;
701} const g_aRdnMap[] =
702{
703 { "0.9.2342.19200300.100.1.3", RT_STR_TUPLE("Mail"), "Rfc822Mailbox" },
704 { "0.9.2342.19200300.100.1.25", RT_STR_TUPLE("DC"), "DomainComponent" },
705 { "1.2.840.113549.1.9.1", RT_STR_TUPLE("Email"), "EmailAddress" },
706 { "2.5.4.3", RT_STR_TUPLE("CN"), "CommonName" },
707 { "2.5.4.4", RT_STR_TUPLE("S"), "Surname" },
708 { "2.5.4.6", RT_STR_TUPLE("C"), "CountryName" },
709 { "2.5.4.7", RT_STR_TUPLE("L"), "LocalityName" },
710 { "2.5.4.8", RT_STR_TUPLE("ST"), "StatOrProviceName" },
711 { "2.5.4.10", RT_STR_TUPLE("O"), "OrganizationName" },
712 { "2.5.4.11", RT_STR_TUPLE("OU"), "OrganizationUnitName" },
713 { "2.5.4.42", RT_STR_TUPLE("G"), "GivenName" },
714 { "2.5.4.43", RT_STR_TUPLE("I"), "Initials" },
715 { "2.5.4.44", RT_STR_TUPLE("GQ"), "GenerationQualifier" },
716};
717
718
719RTDECL(const char *) RTCrX509Name_GetShortRdn(PCRTASN1OBJID pRdnId)
720{
721 uint32_t iName = RT_ELEMENTS(g_aRdnMap);
722 while (iName-- > 0)
723 if (RTAsn1ObjId_CompareWithString(pRdnId, g_aRdnMap[iName].pszOid) == 0)
724 return g_aRdnMap[iName].pszShortNm;
725 return NULL;
726}
727
728
729RTDECL(bool) RTCrX509Name_MatchWithString(PCRTCRX509NAME pThis, const char *pszString)
730{
731 /* Keep track of the string length. */
732 size_t cchString = strlen(pszString);
733
734 /*
735 * The usual double loop for walking the components.
736 */
737 for (uint32_t i = 0; i < pThis->cItems; i++)
738 {
739 PCRTCRX509RELATIVEDISTINGUISHEDNAME pRdn = pThis->papItems[i];
740 for (uint32_t j = 0; j < pRdn->cItems; j++)
741 {
742 PCRTCRX509ATTRIBUTETYPEANDVALUE pComponent = pRdn->papItems[j];
743
744 /*
745 * Must be a string.
746 */
747 if (pComponent->Value.enmType != RTASN1TYPE_STRING)
748 return false;
749
750 /*
751 * Look up the component name prefix and check whether it's also in the string.
752 */
753 uint32_t iName = RT_ELEMENTS(g_aRdnMap);
754 while (iName-- > 0)
755 if (RTAsn1ObjId_CompareWithString(&pComponent->Type, g_aRdnMap[iName].pszOid) == 0)
756 break;
757 AssertMsgReturn(iName != UINT32_MAX, ("Please extend g_aRdnMap with '%s'.\n", pComponent->Type.szObjId), false);
758
759 if ( strncmp(pszString, g_aRdnMap[iName].pszShortNm, g_aRdnMap[iName].cchShortNm) != 0
760 || pszString[g_aRdnMap[iName].cchShortNm] != '=')
761 return false;
762
763 pszString += g_aRdnMap[iName].cchShortNm + 1;
764 cchString -= g_aRdnMap[iName].cchShortNm + 1;
765
766 /*
767 * Compare the component string.
768 */
769 size_t cchComponent;
770 int rc = RTAsn1String_QueryUtf8Len(&pComponent->Value.u.String, &cchComponent);
771 AssertRCReturn(rc, false);
772
773 if (cchComponent > cchString)
774 return false;
775 if (RTAsn1String_CompareWithString(&pComponent->Value.u.String, pszString, cchComponent) != 0)
776 return false;
777
778 cchString -= cchComponent;
779 pszString += cchComponent;
780
781 /*
782 * Check separator comma + space and skip extra spaces before the next component.
783 */
784 if (cchString)
785 {
786 if (pszString[0] != ',')
787 return false;
788 if (pszString[1] != ' ' && pszString[1] != '\t')
789 return false;
790 pszString += 2;
791 cchString -= 2;
792
793 while (*pszString == ' ' || *pszString == '\t')
794 {
795 pszString++;
796 cchString--;
797 }
798 }
799 }
800 }
801
802 /*
803 * If we got thru the whole name and the whole string, we're good.
804 */
805 return *pszString == '\0';
806}
807
808
809RTDECL(int) RTCrX509Name_FormatAsString(PCRTCRX509NAME pThis, char *pszBuf, size_t cbBuf, size_t *pcbActual)
810{
811 /*
812 * The usual double loop for walking the components.
813 */
814 size_t off = 0;
815 int rc = VINF_SUCCESS;
816 for (uint32_t i = 0; i < pThis->cItems; i++)
817 {
818 PCRTCRX509RELATIVEDISTINGUISHEDNAME pRdn = pThis->papItems[i];
819 for (uint32_t j = 0; j < pRdn->cItems; j++)
820 {
821 PCRTCRX509ATTRIBUTETYPEANDVALUE pComponent = pRdn->papItems[j];
822
823 /*
824 * Must be a string.
825 */
826 if (pComponent->Value.enmType != RTASN1TYPE_STRING)
827 return VERR_CR_X509_NAME_NOT_STRING;
828
829 /*
830 * Look up the component name prefix.
831 */
832 uint32_t iName = RT_ELEMENTS(g_aRdnMap);
833 while (iName-- > 0)
834 if (RTAsn1ObjId_CompareWithString(&pComponent->Type, g_aRdnMap[iName].pszOid) == 0)
835 break;
836 AssertMsgReturn(iName != UINT32_MAX, ("Please extend g_aRdnMap with '%s'.\n", pComponent->Type.szObjId),
837 VERR_CR_X509_NAME_MISSING_RDN_MAP_ENTRY);
838
839 /*
840 * Append the prefix.
841 */
842 if (off)
843 {
844 if (off + 2 < cbBuf)
845 {
846 pszBuf[off] = ',';
847 pszBuf[off + 1] = ' ';
848 }
849 else
850 rc = VERR_BUFFER_OVERFLOW;
851 off += 2;
852 }
853
854 if (off + g_aRdnMap[iName].cchShortNm + 1 < cbBuf)
855 {
856 memcpy(&pszBuf[off], g_aRdnMap[iName].pszShortNm, g_aRdnMap[iName].cchShortNm);
857 pszBuf[off + g_aRdnMap[iName].cchShortNm] = '=';
858 }
859 else
860 rc = VERR_BUFFER_OVERFLOW;
861 off += g_aRdnMap[iName].cchShortNm + 1;
862
863 /*
864 * Add the component string.
865 */
866 const char *pszUtf8;
867 size_t cchUtf8;
868 int rc2 = RTAsn1String_QueryUtf8(&pComponent->Value.u.String, &pszUtf8, &cchUtf8);
869 AssertRCReturn(rc2, rc2);
870 if (off + cchUtf8 < cbBuf)
871 memcpy(&pszBuf[off], pszUtf8, cchUtf8);
872 else
873 rc = VERR_BUFFER_OVERFLOW;
874 off += cchUtf8;
875 }
876 }
877
878 if (pcbActual)
879 *pcbActual = off + 1;
880 if (off < cbBuf)
881 pszBuf[off] = '\0';
882 return rc;
883}
884
885
886
887/*
888 * One X.509 GeneralName.
889 */
890
891/**
892 * Name constraint matching (RFC-5280): DNS Name.
893 *
894 * @returns true on match, false on mismatch.
895 * @param pConstraint The constraint name.
896 * @param pName The name to match against the constraint.
897 */
898static bool rtCrX509GeneralName_ConstraintMatchDnsName(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName)
899{
900 /*
901 * Empty constraint string is taken to match everything.
902 */
903 if (pConstraint->u.pT2_DnsName->Asn1Core.cb == 0)
904 return true;
905
906 /*
907 * Get the UTF-8 strings for the two.
908 */
909 size_t cchConstraint;
910 char const *pszConstraint;
911 int rc = RTAsn1String_QueryUtf8(pConstraint->u.pT2_DnsName, &pszConstraint, &cchConstraint);
912 if (RT_SUCCESS(rc))
913 {
914 size_t cchFull;
915 char const *pszFull;
916 rc = RTAsn1String_QueryUtf8(pName->u.pT2_DnsName, &pszFull, &cchFull);
917 if (RT_SUCCESS(rc))
918 {
919 /*
920 * No match if the constraint is longer.
921 */
922 if (cchConstraint > cchFull)
923 return false;
924
925 /*
926 * No match if the constraint and name tail doesn't match
927 * in a case-insensitive compare.
928 */
929 size_t offFull = cchFull - cchConstraint;
930 if (RTStrICmp(&pszFull[offFull], pszConstraint) != 0)
931 return false;
932 if (!offFull)
933 return true;
934
935 /*
936 * The matching constraint must be delimited by a dot in the full
937 * name. There seems to be some discussion whether ".oracle.com"
938 * should match "www..oracle.com". This implementation does choose
939 * to not succeed in that case.
940 */
941 if ((pszFull[offFull - 1] == '.') ^ (pszFull[offFull] == '.'))
942 return true;
943
944 return false;
945 }
946 }
947
948 /* fall back. */
949 return RTCrX509GeneralName_Compare(pConstraint, pName) == 0;
950}
951
952
953/**
954 * Name constraint matching (RFC-5280): RFC-822 (email).
955 *
956 * @returns true on match, false on mismatch.
957 * @param pConstraint The constraint name.
958 * @param pName The name to match against the constraint.
959 */
960static bool rtCrX509GeneralName_ConstraintMatchRfc822Name(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName)
961{
962 /*
963 * Empty constraint string is taken to match everything.
964 */
965 if (pConstraint->u.pT1_Rfc822->Asn1Core.cb == 0)
966 return true;
967
968 /*
969 * Get the UTF-8 strings for the two.
970 */
971 size_t cchConstraint;
972 char const *pszConstraint;
973 int rc = RTAsn1String_QueryUtf8(pConstraint->u.pT1_Rfc822, &pszConstraint, &cchConstraint);
974 if (RT_SUCCESS(rc))
975 {
976 size_t cchFull;
977 char const *pszFull;
978 rc = RTAsn1String_QueryUtf8(pName->u.pT1_Rfc822, &pszFull, &cchFull);
979 if (RT_SUCCESS(rc))
980 {
981 /*
982 * No match if the constraint is longer.
983 */
984 if (cchConstraint > cchFull)
985 return false;
986
987 /*
988 * A lone dot matches everything.
989 */
990 if (cchConstraint == 1 && *pszConstraint == '.')
991 return true;
992
993 /*
994 * If there is a '@' in the constraint, the entire address must match.
995 */
996 const char *pszConstraintAt = (const char *)memchr(pszConstraint, '@', cchConstraint);
997 if (pszConstraintAt)
998 return cchConstraint == cchFull && RTStrICmp(pszConstraint, pszFull) == 0;
999
1000 /*
1001 * No match if the constraint and name tail doesn't match
1002 * in a case-insensitive compare.
1003 */
1004 size_t offFull = cchFull - cchConstraint;
1005 if (RTStrICmp(&pszFull[offFull], pszConstraint) != 0)
1006 return false;
1007
1008 /*
1009 * If the constraint starts with a dot, we're supposed to be
1010 * satisfied with a tail match.
1011 */
1012 /** @todo Check if this should match even if offFull == 0. */
1013 if (*pszConstraint == '.')
1014 return true;
1015
1016 /*
1017 * Otherwise, we require a hostname match and thus expect an '@'
1018 * immediatly preceding the constraint match.
1019 */
1020 if (pszFull[offFull - 1] == '@')
1021 return true;
1022
1023 return false;
1024 }
1025 }
1026
1027 /* fall back. */
1028 return RTCrX509GeneralName_Compare(pConstraint, pName) == 0;
1029}
1030
1031
1032/**
1033 * Extracts the hostname from an URI.
1034 *
1035 * @returns true if successfully extract, false if no hostname present.
1036 * @param pszUri The URI.
1037 * @param pchHostName .
1038 * @param pcchHostName .
1039 */
1040static bool rtCrX509GeneralName_ExtractHostName(const char *pszUri, const char **pchHostName, size_t *pcchHostName)
1041{
1042 /*
1043 * Skip the schema name.
1044 */
1045 const char *pszStart = strchr(pszUri, ':');
1046 while (pszStart && (pszStart[1] != '/' || pszStart[2] != '/'))
1047 pszStart = strchr(pszStart + 1, ':');
1048 if (pszStart)
1049 {
1050 pszStart += 3;
1051
1052 /*
1053 * The name ends with the first slash or ":port".
1054 */
1055 const char *pszEnd = strchr(pszStart, '/');
1056 if (!pszEnd)
1057 pszEnd = strchr(pszStart, '\0');
1058 if (memchr(pszStart, ':', pszEnd - pszStart))
1059 do
1060 pszEnd--;
1061 while (*pszEnd != ':');
1062 if (pszEnd != pszStart)
1063 {
1064 /*
1065 * Drop access credentials at the front of the string if present.
1066 */
1067 const char *pszAt = (const char *)memchr(pszStart, '@', pszEnd - pszStart);
1068 if (pszAt)
1069 pszStart = pszAt + 1;
1070
1071 /*
1072 * If there is still some string left, that's the host name.
1073 */
1074 if (pszEnd != pszStart)
1075 {
1076 *pcchHostName = pszEnd - pszStart;
1077 *pchHostName = pszStart;
1078 return true;
1079 }
1080 }
1081 }
1082
1083 *pcchHostName = 0;
1084 *pchHostName = NULL;
1085 return false;
1086}
1087
1088
1089/**
1090 * Name constraint matching (RFC-5280): URI.
1091 *
1092 * @returns true on match, false on mismatch.
1093 * @param pConstraint The constraint name.
1094 * @param pName The name to match against the constraint.
1095 */
1096static bool rtCrX509GeneralName_ConstraintMatchUri(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName)
1097{
1098 /*
1099 * Empty constraint string is taken to match everything.
1100 */
1101 if (pConstraint->u.pT6_Uri->Asn1Core.cb == 0)
1102 return true;
1103
1104 /*
1105 * Get the UTF-8 strings for the two.
1106 */
1107 size_t cchConstraint;
1108 char const *pszConstraint;
1109 int rc = RTAsn1String_QueryUtf8(pConstraint->u.pT6_Uri, &pszConstraint, &cchConstraint);
1110 if (RT_SUCCESS(rc))
1111 {
1112 size_t cchFull;
1113 char const *pszFull;
1114 rc = RTAsn1String_QueryUtf8(pName->u.pT6_Uri, &pszFull, &cchFull);
1115 if (RT_SUCCESS(rc))
1116 {
1117 /*
1118 * Isolate the hostname in the name.
1119 */
1120 size_t cchHostName;
1121 const char *pchHostName;
1122 if (rtCrX509GeneralName_ExtractHostName(pszFull, &pchHostName, &cchHostName))
1123 {
1124 /*
1125 * Domain constraint.
1126 */
1127 if (*pszConstraint == '.')
1128 {
1129 if (cchHostName >= cchConstraint)
1130 {
1131 size_t offHostName = cchHostName - cchConstraint;
1132 if (RTStrICmp(&pchHostName[offHostName], pszConstraint) == 0)
1133 {
1134 /* "http://www..oracle.com" does not match ".oracle.com".
1135 It's debatable whether "http://.oracle.com/" should match. */
1136 if ( !offHostName
1137 || pchHostName[offHostName - 1] != '.')
1138 return true;
1139 }
1140 }
1141 }
1142 /*
1143 * Host name constraint. Full match required.
1144 */
1145 else if ( cchHostName == cchConstraint
1146 && RTStrNICmp(pchHostName, pszConstraint, cchHostName) == 0)
1147 return true;
1148 }
1149 return false;
1150 }
1151 }
1152
1153 /* fall back. */
1154 return RTCrX509GeneralName_Compare(pConstraint, pName) == 0;
1155}
1156
1157
1158/**
1159 * Name constraint matching (RFC-5280): IP address.
1160 *
1161 * @returns true on match, false on mismatch.
1162 * @param pConstraint The constraint name.
1163 * @param pName The name to match against the constraint.
1164 */
1165static bool rtCrX509GeneralName_ConstraintMatchIpAddress(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName)
1166{
1167 uint8_t const *pbConstraint = pConstraint->u.pT7_IpAddress->Asn1Core.uData.pu8;
1168 uint8_t const *pbFull = pName->u.pT7_IpAddress->Asn1Core.uData.pu8;
1169
1170 /*
1171 * IPv4.
1172 */
1173 if ( pConstraint->u.pT7_IpAddress->Asn1Core.cb == 8 /* ip+netmask*/
1174 && pName->u.pT7_IpAddress->Asn1Core.cb == 4) /* ip */
1175 return ((pbFull[0] ^ pbConstraint[0]) & pbConstraint[4]) == 0
1176 && ((pbFull[1] ^ pbConstraint[1]) & pbConstraint[5]) == 0
1177 && ((pbFull[2] ^ pbConstraint[2]) & pbConstraint[6]) == 0
1178 && ((pbFull[3] ^ pbConstraint[3]) & pbConstraint[7]) == 0;
1179
1180 /*
1181 * IPv6.
1182 */
1183 if ( pConstraint->u.pT7_IpAddress->Asn1Core.cb == 32 /* ip+netmask*/
1184 && pName->u.pT7_IpAddress->Asn1Core.cb == 16) /* ip */
1185 {
1186 for (uint32_t i = 0; i < 16; i++)
1187 if (((pbFull[i] ^ pbConstraint[i]) & pbConstraint[i + 16]) != 0)
1188 return false;
1189 return true;
1190 }
1191
1192 return RTCrX509GeneralName_Compare(pConstraint, pName) == 0;
1193}
1194
1195
1196RTDECL(bool) RTCrX509GeneralName_ConstraintMatch(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName)
1197{
1198 if (pConstraint->enmChoice == pName->enmChoice)
1199 {
1200 if (RTCRX509GENERALNAME_IS_DIRECTORY_NAME(pConstraint))
1201 return RTCrX509Name_ConstraintMatch(&pConstraint->u.pT4->DirectoryName, &pName->u.pT4->DirectoryName);
1202
1203 if (RTCRX509GENERALNAME_IS_DNS_NAME(pConstraint))
1204 return rtCrX509GeneralName_ConstraintMatchDnsName(pConstraint, pName);
1205
1206 if (RTCRX509GENERALNAME_IS_RFC822_NAME(pConstraint))
1207 return rtCrX509GeneralName_ConstraintMatchRfc822Name(pConstraint, pName);
1208
1209 if (RTCRX509GENERALNAME_IS_URI(pConstraint))
1210 return rtCrX509GeneralName_ConstraintMatchUri(pConstraint, pName);
1211
1212 if (RTCRX509GENERALNAME_IS_IP_ADDRESS(pConstraint))
1213 return rtCrX509GeneralName_ConstraintMatchIpAddress(pConstraint, pName);
1214
1215 AssertFailed();
1216 return RTCrX509GeneralName_Compare(pConstraint, pName) == 0;
1217 }
1218 return false;
1219}
1220
1221
1222/*
1223 * Sequence of X.509 GeneralNames.
1224 */
1225
1226
1227/*
1228 * X.509 UniqueIdentifier.
1229 */
1230
1231
1232/*
1233 * X.509 SubjectPublicKeyInfo.
1234 */
1235
1236
1237/*
1238 * X.509 AuthorityKeyIdentifier (IPRT representation).
1239 */
1240
1241
1242/*
1243 * One X.509 PolicyQualifierInfo.
1244 */
1245
1246
1247/*
1248 * Sequence of X.509 PolicyQualifierInfo.
1249 */
1250
1251
1252/*
1253 * One X.509 PolicyInformation.
1254 */
1255
1256
1257/*
1258 * Sequence of X.509 CertificatePolicies.
1259 */
1260
1261
1262/*
1263 * One X.509 PolicyMapping (IPRT representation).
1264 */
1265
1266
1267/*
1268 * Sequence of X.509 PolicyMappings (IPRT representation).
1269 */
1270
1271
1272/*
1273 * X.509 BasicConstraints (IPRT representation).
1274 */
1275
1276
1277/*
1278 * X.509 GeneralSubtree (IPRT representation).
1279 */
1280
1281
1282RTDECL(bool) RTCrX509GeneralSubtree_ConstraintMatch(PCRTCRX509GENERALSUBTREE pConstraint, PCRTCRX509GENERALSUBTREE pName)
1283{
1284 return RTCrX509GeneralName_ConstraintMatch(&pConstraint->Base, &pName->Base);
1285}
1286
1287
1288/*
1289 * Sequence of X.509 GeneralSubtrees (IPRT representation).
1290 */
1291
1292
1293/*
1294 * X.509 NameConstraints (IPRT representation).
1295 */
1296
1297
1298/*
1299 * X.509 PolicyConstraints (IPRT representation).
1300 */
1301
1302
1303/*
1304 * One X.509 Extension.
1305 */
1306
1307
1308/*
1309 * Sequence of X.509 Extensions.
1310 */
1311
1312
1313/*
1314 * X.509 TbsCertificate.
1315 */
1316
1317static void rtCrx509TbsCertificate_AddKeyUsageFlags(PRTCRX509TBSCERTIFICATE pThis, PCRTCRX509EXTENSION pExtension)
1318{
1319 AssertReturnVoid(pExtension->enmValue == RTCRX509EXTENSIONVALUE_BIT_STRING);
1320 /* 3 = 1 byte for unused bit count, followed by one or two bytes containing actual bits. RFC-5280 defines bits 0 thru 8. */
1321 AssertReturnVoid(pExtension->ExtnValue.pEncapsulated->cb <= 3);
1322 pThis->T3.fKeyUsage |= (uint32_t)RTAsn1BitString_GetAsUInt64((PCRTASN1BITSTRING)pExtension->ExtnValue.pEncapsulated);
1323}
1324
1325
1326static void rtCrx509TbsCertificate_AddExtKeyUsageFlags(PRTCRX509TBSCERTIFICATE pThis, PCRTCRX509EXTENSION pExtension)
1327{
1328 AssertReturnVoid(pExtension->enmValue == RTCRX509EXTENSIONVALUE_SEQ_OF_OBJ_IDS);
1329 PCRTASN1SEQOFOBJIDS pObjIds = (PCRTASN1SEQOFOBJIDS)pExtension->ExtnValue.pEncapsulated;
1330 uint32_t i = pObjIds->cItems;
1331 while (i-- > 0)
1332 {
1333
1334 if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_ANY_EXTENDED_KEY_USAGE_OID) == 0)
1335 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_ANY;
1336 else if (RTAsn1ObjId_StartsWith(pObjIds->papItems[i], RTCRX509_ID_KP_OID))
1337 {
1338 if (RTAsn1ObjIdCountComponents(pObjIds->papItems[i]) == 9)
1339 switch (RTAsn1ObjIdGetLastComponentsAsUInt32(pObjIds->papItems[i]))
1340 {
1341 case 1: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_SERVER_AUTH; break;
1342 case 2: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_CLIENT_AUTH; break;
1343 case 3: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_CODE_SIGNING; break;
1344 case 4: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_EMAIL_PROTECTION; break;
1345 case 5: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_IPSEC_END_SYSTEM; break;
1346 case 6: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_IPSEC_TUNNEL; break;
1347 case 7: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_IPSEC_USER; break;
1348 case 8: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_TIMESTAMPING; break;
1349 case 9: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OCSP_SIGNING; break;
1350 case 10: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_DVCS; break;
1351 case 11: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_SBGP_CERT_AA_SERVICE_AUTH; break;
1352 case 13: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_EAP_OVER_PPP; break;
1353 case 14: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_EAP_OVER_LAN; break;
1354 default: pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OTHER; break;
1355 }
1356 else
1357 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OTHER;
1358 }
1359 else if (RTAsn1ObjId_StartsWith(pObjIds->papItems[i], RTCRX509_APPLE_EKU_APPLE_EXTENDED_KEY_USAGE_OID))
1360 {
1361 if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_CODE_SIGNING_OID) == 0)
1362 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING;
1363 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_CODE_SIGNING_DEVELOPMENT_OID) == 0)
1364 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_DEVELOPMENT;
1365 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_SOFTWARE_UPDATE_SIGNING_OID) == 0)
1366 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_SOFTWARE_UPDATE_SIGNING;
1367 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_CODE_SIGNING_THRID_PARTY_OID) == 0)
1368 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_THIRD_PARTY;
1369 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_RESOURCE_SIGNING_OID) == 0)
1370 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_RESOURCE_SIGNING;
1371 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_APPLE_EKU_SYSTEM_IDENTITY_OID) == 0)
1372 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_APPLE_SYSTEM_IDENTITY;
1373 else
1374 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OTHER;
1375 }
1376 else if (RTAsn1ObjId_StartsWith(pObjIds->papItems[i], "1.3.6.1.4.1.311"))
1377 {
1378 if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_TIMESTAMP_SIGNING_OID) == 0)
1379 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING;
1380 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_NT5_CRYPTO_OID) == 0)
1381 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_NT5_CRYPTO;
1382 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_OEM_WHQL_CRYPTO_OID) == 0)
1383 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_OEM_WHQL_CRYPTO;
1384 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_EMBEDDED_NT_CRYPTO_OID) == 0)
1385 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_EMBEDDED_NT_CRYPTO;
1386 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_KERNEL_MODE_CODE_SIGNING_OID) == 0)
1387 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_KERNEL_MODE_CODE_SIGNING;
1388 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_LIFETIME_SIGNING_OID) == 0)
1389 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_LIFETIME_SIGNING;
1390 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_DRM_OID) == 0)
1391 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_DRM;
1392 else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_DRM_INDIVIDUALIZATION_OID) == 0)
1393 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_DRM_INDIVIDUALIZATION;
1394 else
1395 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OTHER;
1396 }
1397 else
1398 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_OTHER;
1399 }
1400}
1401
1402
1403/**
1404 * (Re-)Process the certificate extensions.
1405 *
1406 * Will fail if duplicate extensions are encountered.
1407 *
1408 * @returns IPRT status code.
1409 * @param pThis The to-be-signed certificate part.
1410 * @param pErrInfo Where to return extended error details,
1411 * optional.
1412 */
1413RTDECL(int) RTCrX509TbsCertificate_ReprocessExtensions(PRTCRX509TBSCERTIFICATE pThis, PRTERRINFO pErrInfo)
1414{
1415 /*
1416 * Clear all variables we will set.
1417 */
1418 pThis->T3.fFlags = 0;
1419 pThis->T3.fKeyUsage = 0;
1420 pThis->T3.fExtKeyUsage = 0;
1421 pThis->T3.pAuthorityKeyIdentifier = NULL;
1422 pThis->T3.pSubjectKeyIdentifier = NULL;
1423 pThis->T3.pAltSubjectName = NULL;
1424 pThis->T3.pAltIssuerName = NULL;
1425 pThis->T3.pCertificatePolicies = NULL;
1426 pThis->T3.pPolicyMappings = NULL;
1427 pThis->T3.pBasicConstraints = NULL;
1428 pThis->T3.pNameConstraints = NULL;
1429 pThis->T3.pPolicyConstraints = NULL;
1430 pThis->T3.pInhibitAnyPolicy = NULL;
1431
1432#define CHECK_SET_PRESENT_RET_ON_DUP(a_pThis, a_pErrInfo, a_fPresentFlag) \
1433 do { \
1434 if ((a_pThis)->T3.fFlags & (a_fPresentFlag)) \
1435 return RTErrInfoSet(a_pErrInfo, VERR_CR_X509_TBSCERT_DUPLICATE_EXTENSION, \
1436 "Duplicate extension " #a_fPresentFlag); \
1437 (a_pThis)->T3.fFlags |= (a_fPresentFlag); \
1438 } while (0)
1439
1440 /*
1441 * Process all the extensions.
1442 */
1443 for (uint32_t i = 0; i < pThis->T3.Extensions.cItems; i++)
1444 {
1445 PCRTASN1OBJID pExtnId = &pThis->T3.Extensions.papItems[i]->ExtnId;
1446 PCRTASN1OCTETSTRING pExtValue = &pThis->T3.Extensions.papItems[i]->ExtnValue;
1447 if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_KEY_USAGE_OID) == 0)
1448 {
1449 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE);
1450 rtCrx509TbsCertificate_AddKeyUsageFlags(pThis, pThis->T3.Extensions.papItems[i]);
1451 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_BIT_STRING);
1452 }
1453 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_EXT_KEY_USAGE_OID) == 0)
1454 {
1455 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_EXT_KEY_USAGE);
1456 rtCrx509TbsCertificate_AddExtKeyUsageFlags(pThis, pThis->T3.Extensions.papItems[i]);
1457 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_SEQ_OF_OBJ_IDS);
1458 }
1459 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_AUTHORITY_KEY_IDENTIFIER_OID) == 0)
1460 {
1461 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_AUTHORITY_KEY_IDENTIFIER);
1462 pThis->T3.pAuthorityKeyIdentifier = (PCRTCRX509AUTHORITYKEYIDENTIFIER)pExtValue->pEncapsulated;
1463 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_AUTHORITY_KEY_IDENTIFIER);
1464 }
1465 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_OLD_AUTHORITY_KEY_IDENTIFIER_OID) == 0)
1466 {
1467 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_OLD_AUTHORITY_KEY_IDENTIFIER);
1468 pThis->T3.pOldAuthorityKeyIdentifier = (PCRTCRX509OLDAUTHORITYKEYIDENTIFIER)pExtValue->pEncapsulated;
1469 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_OLD_AUTHORITY_KEY_IDENTIFIER);
1470 }
1471 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_SUBJECT_KEY_IDENTIFIER_OID) == 0)
1472 {
1473 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_KEY_IDENTIFIER);
1474 pThis->T3.pSubjectKeyIdentifier = (PCRTASN1OCTETSTRING)pExtValue->pEncapsulated;
1475 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_OCTET_STRING);
1476 }
1477 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID) == 0)
1478 {
1479 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_ALT_NAME);
1480 pThis->T3.pAltSubjectName = (PCRTCRX509GENERALNAMES)pExtValue->pEncapsulated;
1481 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_GENERAL_NAMES);
1482 }
1483 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_ISSUER_ALT_NAME_OID) == 0)
1484 {
1485 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_ISSUER_ALT_NAME);
1486 pThis->T3.pAltIssuerName = (PCRTCRX509GENERALNAMES)pExtValue->pEncapsulated;
1487 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_GENERAL_NAMES);
1488 }
1489 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_CERTIFICATE_POLICIES_OID) == 0)
1490 {
1491 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_CERTIFICATE_POLICIES);
1492 pThis->T3.pCertificatePolicies = (PCRTCRX509CERTIFICATEPOLICIES)pExtValue->pEncapsulated;
1493 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_CERTIFICATE_POLICIES);
1494 }
1495 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_POLICY_MAPPINGS_OID) == 0)
1496 {
1497 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_MAPPINGS);
1498 pThis->T3.pPolicyMappings = (PCRTCRX509POLICYMAPPINGS)pExtValue->pEncapsulated;
1499 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_POLICY_MAPPINGS);
1500 }
1501 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_BASIC_CONSTRAINTS_OID) == 0)
1502 {
1503 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_BASIC_CONSTRAINTS);
1504 pThis->T3.pBasicConstraints = (PCRTCRX509BASICCONSTRAINTS)pExtValue->pEncapsulated;
1505 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_BASIC_CONSTRAINTS);
1506 }
1507 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_NAME_CONSTRAINTS_OID) == 0)
1508 {
1509 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_NAME_CONSTRAINTS);
1510 pThis->T3.pNameConstraints = (PCRTCRX509NAMECONSTRAINTS)pExtValue->pEncapsulated;
1511 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_NAME_CONSTRAINTS);
1512 }
1513 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_POLICY_CONSTRAINTS_OID) == 0)
1514 {
1515 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_CONSTRAINTS);
1516 pThis->T3.pPolicyConstraints = (PCRTCRX509POLICYCONSTRAINTS)pExtValue->pEncapsulated;
1517 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_POLICY_CONSTRAINTS);
1518 }
1519 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_INHIBIT_ANY_POLICY_OID) == 0)
1520 {
1521 CHECK_SET_PRESENT_RET_ON_DUP(pThis, pErrInfo, RTCRX509TBSCERTIFICATE_F_PRESENT_INHIBIT_ANY_POLICY);
1522 pThis->T3.pInhibitAnyPolicy = (PCRTASN1INTEGER)pExtValue->pEncapsulated;
1523 Assert(pThis->T3.Extensions.papItems[i]->enmValue == RTCRX509EXTENSIONVALUE_INTEGER);
1524 }
1525 else if (RTAsn1ObjId_CompareWithString(pExtnId, RTCRX509_ID_CE_ACCEPTABLE_CERT_POLICIES_OID) == 0)
1526 pThis->T3.fFlags |= RTCRX509TBSCERTIFICATE_F_PRESENT_ACCEPTABLE_CERT_POLICIES;
1527 else
1528 pThis->T3.fFlags |= RTCRX509TBSCERTIFICATE_F_PRESENT_OTHER;
1529 }
1530
1531 if (!pThis->T3.fFlags)
1532 pThis->T3.fFlags |= RTCRX509TBSCERTIFICATE_F_PRESENT_NONE;
1533
1534#undef CHECK_SET_PRESENT_RET_ON_DUP
1535 return VINF_SUCCESS;
1536}
1537
1538
1539
1540/*
1541 * One X.509 Certificate.
1542 */
1543
1544RTDECL(bool) RTCrX509Certificate_MatchIssuerAndSerialNumber(PCRTCRX509CERTIFICATE pCertificate,
1545 PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNumber)
1546{
1547 if ( RTAsn1Integer_UnsignedCompare(&pCertificate->TbsCertificate.SerialNumber, pSerialNumber) == 0
1548 && RTCrX509Name_Compare(&pCertificate->TbsCertificate.Issuer, pIssuer) == 0)
1549 return true;
1550 return false;
1551}
1552
1553
1554RTDECL(bool) RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(PCRTCRX509CERTIFICATE pThis, PCRTCRX509NAME pName)
1555{
1556 if (RTCrX509Name_MatchByRfc5280(&pThis->TbsCertificate.Subject, pName))
1557 return true;
1558
1559 if (RTCrX509Extensions_IsPresent(&pThis->TbsCertificate.T3.Extensions))
1560 for (uint32_t i = 0; i < pThis->TbsCertificate.T3.Extensions.cItems; i++)
1561 {
1562 PCRTCRX509EXTENSION pExt = pThis->TbsCertificate.T3.Extensions.papItems[i];
1563 if ( pExt->enmValue == RTCRX509EXTENSIONVALUE_GENERAL_NAMES
1564 && RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID))
1565 {
1566 PCRTCRX509GENERALNAMES pGeneralNames = (PCRTCRX509GENERALNAMES)pExt->ExtnValue.pEncapsulated;
1567 for (uint32_t j = 0; j < pGeneralNames->cItems; j++)
1568 if ( RTCRX509GENERALNAME_IS_DIRECTORY_NAME(pGeneralNames->papItems[j])
1569 && RTCrX509Name_MatchByRfc5280(&pGeneralNames->papItems[j]->u.pT4->DirectoryName, pName))
1570 return true;
1571 }
1572 }
1573 return false;
1574}
1575
1576
1577RTDECL(bool) RTCrX509Certificate_IsSelfSigned(PCRTCRX509CERTIFICATE pCertificate)
1578{
1579 if (RTCrX509Certificate_IsPresent(pCertificate))
1580 {
1581 return RTCrX509Name_MatchByRfc5280(&pCertificate->TbsCertificate.Subject,
1582 &pCertificate->TbsCertificate.Issuer);
1583 }
1584 return false;
1585}
1586
1587
1588/*
1589 * Set of X.509 Certificates.
1590 */
1591
1592RTDECL(PCRTCRX509CERTIFICATE)
1593RTCrX509Certificates_FindByIssuerAndSerialNumber(PCRTCRX509CERTIFICATES pCertificates,
1594 PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNumber)
1595{
1596 for (uint32_t i = 0; i < pCertificates->cItems; i++)
1597 if (RTCrX509Certificate_MatchIssuerAndSerialNumber(pCertificates->papItems[i], pIssuer, pSerialNumber))
1598 return pCertificates->papItems[i];
1599 return NULL;
1600}
1601
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette