/src/nss/lib/certdb/xbsconst.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | /* |
6 | | * X.509 v3 Basic Constraints Extension |
7 | | */ |
8 | | |
9 | | #include "prtypes.h" |
10 | | #include <limits.h> /* for LONG_MAX */ |
11 | | #include "seccomon.h" |
12 | | #include "secdert.h" |
13 | | #include "secoidt.h" |
14 | | #include "secasn1t.h" |
15 | | #include "secasn1.h" |
16 | | #include "certt.h" |
17 | | #include "secder.h" |
18 | | #include "prprf.h" |
19 | | #include "secerr.h" |
20 | | |
21 | | typedef struct EncodedContext { |
22 | | SECItem isCA; |
23 | | SECItem pathLenConstraint; |
24 | | SECItem encodedValue; |
25 | | PLArenaPool *arena; |
26 | | } EncodedContext; |
27 | | |
28 | | static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = { |
29 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncodedContext) }, |
30 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ |
31 | | offsetof(EncodedContext, isCA) }, |
32 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, |
33 | | offsetof(EncodedContext, pathLenConstraint) }, |
34 | | { 0 } |
35 | | }; |
36 | | |
37 | | static unsigned char hexTrue = 0xff; |
38 | | static unsigned char hexFalse = 0x00; |
39 | | |
40 | | #define GEN_BREAK(status) \ |
41 | 0 | rv = status; \ |
42 | 0 | break; |
43 | | |
44 | | SECStatus |
45 | | CERT_EncodeBasicConstraintValue(PLArenaPool *arena, CERTBasicConstraints *value, |
46 | | SECItem *encodedValue) |
47 | 0 | { |
48 | 0 | EncodedContext encodeContext; |
49 | 0 | PLArenaPool *our_pool = NULL; |
50 | 0 | SECStatus rv = SECSuccess; |
51 | |
|
52 | 0 | do { |
53 | 0 | PORT_Memset(&encodeContext, 0, sizeof(encodeContext)); |
54 | 0 | if (!value->isCA && value->pathLenConstraint >= 0) { |
55 | 0 | PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); |
56 | 0 | GEN_BREAK(SECFailure); |
57 | 0 | } |
58 | | |
59 | 0 | encodeContext.arena = arena; |
60 | 0 | if (value->isCA == PR_TRUE) { |
61 | 0 | encodeContext.isCA.data = &hexTrue; |
62 | 0 | encodeContext.isCA.len = 1; |
63 | 0 | } |
64 | | |
65 | | /* If the pathLenConstraint is less than 0, then it should be |
66 | | * omitted from the encoding. |
67 | | */ |
68 | 0 | if (value->isCA && value->pathLenConstraint >= 0) { |
69 | 0 | our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
70 | 0 | if (our_pool == NULL) { |
71 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
72 | 0 | GEN_BREAK(SECFailure); |
73 | 0 | } |
74 | 0 | if (SEC_ASN1EncodeUnsignedInteger( |
75 | 0 | our_pool, &encodeContext.pathLenConstraint, |
76 | 0 | (unsigned long)value->pathLenConstraint) == NULL) { |
77 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
78 | 0 | GEN_BREAK(SECFailure); |
79 | 0 | } |
80 | 0 | } |
81 | 0 | if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext, |
82 | 0 | CERTBasicConstraintsTemplate) == NULL) { |
83 | 0 | GEN_BREAK(SECFailure); |
84 | 0 | } |
85 | 0 | } while (0); |
86 | 0 | if (our_pool) |
87 | 0 | PORT_FreeArena(our_pool, PR_FALSE); |
88 | 0 | return (rv); |
89 | 0 | } |
90 | | |
91 | | SECStatus |
92 | | CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value, |
93 | | const SECItem *encodedValue) |
94 | 0 | { |
95 | 0 | EncodedContext decodeContext; |
96 | 0 | PORTCheapArenaPool tmpArena; |
97 | 0 | SECStatus rv = SECSuccess; |
98 | |
|
99 | 0 | do { |
100 | 0 | PORT_Memset(&decodeContext, 0, sizeof(decodeContext)); |
101 | | /* initialize the value just in case we got "0x30 00", or when the |
102 | | pathLenConstraint is omitted. |
103 | | */ |
104 | 0 | decodeContext.isCA.data = &hexFalse; |
105 | 0 | decodeContext.isCA.len = 1; |
106 | |
|
107 | 0 | PORT_InitCheapArena(&tmpArena, SEC_ASN1_DEFAULT_ARENA_SIZE); |
108 | |
|
109 | 0 | rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodeContext, |
110 | 0 | CERTBasicConstraintsTemplate, encodedValue); |
111 | 0 | if (rv == SECFailure) |
112 | 0 | break; |
113 | | |
114 | 0 | value->isCA = decodeContext.isCA.data |
115 | 0 | ? (PRBool)(decodeContext.isCA.data[0] != 0) |
116 | 0 | : PR_FALSE; |
117 | 0 | if (decodeContext.pathLenConstraint.data == NULL) { |
118 | | /* if the pathLenConstraint is not encoded, and the current setting |
119 | | is CA, then the pathLenConstraint should be set to a negative |
120 | | number |
121 | | for unlimited certificate path. |
122 | | */ |
123 | 0 | if (value->isCA) { |
124 | 0 | value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; |
125 | 0 | } else { |
126 | 0 | value->pathLenConstraint = 0; |
127 | 0 | } |
128 | 0 | } else if (value->isCA) { |
129 | 0 | long len = DER_GetInteger(&decodeContext.pathLenConstraint); |
130 | 0 | if (len < 0 || len == LONG_MAX) { |
131 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
132 | 0 | GEN_BREAK(SECFailure); |
133 | 0 | } |
134 | 0 | value->pathLenConstraint = len; |
135 | 0 | } else { |
136 | | /* here we get an error where the subject is not a CA, but |
137 | | the pathLenConstraint is set */ |
138 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
139 | 0 | GEN_BREAK(SECFailure); |
140 | 0 | break; |
141 | 0 | } |
142 | 0 | } while (0); |
143 | | |
144 | 0 | PORT_DestroyCheapArena(&tmpArena); |
145 | 0 | return (rv); |
146 | 0 | } |