|
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 * Support for various policy related extensions |
|
7 */ |
|
8 |
|
9 #include "seccomon.h" |
|
10 #include "secport.h" |
|
11 #include "secder.h" |
|
12 #include "cert.h" |
|
13 #include "secoid.h" |
|
14 #include "secasn1.h" |
|
15 #include "secerr.h" |
|
16 #include "nspr.h" |
|
17 #include "secutil.h" |
|
18 |
|
19 /* This implementation is derived from the one in nss/lib/certdb/policyxtn.c . |
|
20 ** The chief difference is the addition of the OPTIONAL flag to many |
|
21 ** parts. The idea is to be able to parse and print as much of the |
|
22 ** policy extension as possible, even if some parts are invalid. |
|
23 ** |
|
24 ** If this approach still is unable to decode policy extensions that |
|
25 ** contain invalid parts, then the next approach will be to parse |
|
26 ** the PolicyInfos as a SEQUENCE of ANYs, and then parse each of them |
|
27 ** as PolicyInfos, with the PolicyQualifiers being ANYs, and finally |
|
28 ** parse each of the PolicyQualifiers. |
|
29 */ |
|
30 |
|
31 static const SEC_ASN1Template secu_PolicyQualifierTemplate[] = { |
|
32 { SEC_ASN1_SEQUENCE, |
|
33 0, NULL, sizeof(CERTPolicyQualifier) }, |
|
34 { SEC_ASN1_OBJECT_ID, |
|
35 offsetof(CERTPolicyQualifier, qualifierID) }, |
|
36 { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, |
|
37 offsetof(CERTPolicyQualifier, qualifierValue) }, |
|
38 { 0 } |
|
39 }; |
|
40 |
|
41 static const SEC_ASN1Template secu_PolicyInfoTemplate[] = { |
|
42 { SEC_ASN1_SEQUENCE, |
|
43 0, NULL, sizeof(CERTPolicyInfo) }, |
|
44 { SEC_ASN1_OBJECT_ID, |
|
45 offsetof(CERTPolicyInfo, policyID) }, |
|
46 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL, |
|
47 offsetof(CERTPolicyInfo, policyQualifiers), |
|
48 secu_PolicyQualifierTemplate }, |
|
49 { 0 } |
|
50 }; |
|
51 |
|
52 static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = { |
|
53 { SEC_ASN1_SEQUENCE_OF, |
|
54 offsetof(CERTCertificatePolicies, policyInfos), |
|
55 secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) } |
|
56 }; |
|
57 |
|
58 |
|
59 static CERTCertificatePolicies * |
|
60 secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) |
|
61 { |
|
62 PLArenaPool *arena = NULL; |
|
63 SECStatus rv; |
|
64 CERTCertificatePolicies *policies; |
|
65 CERTPolicyInfo **policyInfos, *policyInfo; |
|
66 CERTPolicyQualifier **policyQualifiers, *policyQualifier; |
|
67 SECItem newExtnValue; |
|
68 |
|
69 /* make a new arena */ |
|
70 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
71 |
|
72 if ( !arena ) { |
|
73 goto loser; |
|
74 } |
|
75 |
|
76 /* allocate the certifiate policies structure */ |
|
77 policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); |
|
78 if ( policies == NULL ) { |
|
79 goto loser; |
|
80 } |
|
81 |
|
82 policies->arena = arena; |
|
83 |
|
84 /* copy the DER into the arena, since Quick DER returns data that points |
|
85 into the DER input, which may get freed by the caller */ |
|
86 rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); |
|
87 if ( rv != SECSuccess ) { |
|
88 goto loser; |
|
89 } |
|
90 |
|
91 /* decode the policy info */ |
|
92 rv = SEC_QuickDERDecodeItem(arena, policies, |
|
93 secu_CertificatePoliciesTemplate, |
|
94 &newExtnValue); |
|
95 |
|
96 if ( rv != SECSuccess ) { |
|
97 goto loser; |
|
98 } |
|
99 |
|
100 /* initialize the oid tags */ |
|
101 policyInfos = policies->policyInfos; |
|
102 while (policyInfos != NULL && *policyInfos != NULL ) { |
|
103 policyInfo = *policyInfos; |
|
104 policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); |
|
105 policyQualifiers = policyInfo->policyQualifiers; |
|
106 while ( policyQualifiers && *policyQualifiers != NULL ) { |
|
107 policyQualifier = *policyQualifiers; |
|
108 policyQualifier->oid = |
|
109 SECOID_FindOIDTag(&policyQualifier->qualifierID); |
|
110 policyQualifiers++; |
|
111 } |
|
112 policyInfos++; |
|
113 } |
|
114 |
|
115 return(policies); |
|
116 |
|
117 loser: |
|
118 if ( arena != NULL ) { |
|
119 PORT_FreeArena(arena, PR_FALSE); |
|
120 } |
|
121 |
|
122 return(NULL); |
|
123 } |
|
124 |
|
125 |
|
126 static char * |
|
127 itemToString(SECItem *item) |
|
128 { |
|
129 char *string; |
|
130 |
|
131 string = PORT_ZAlloc(item->len+1); |
|
132 if (string == NULL) return NULL; |
|
133 PORT_Memcpy(string,item->data,item->len); |
|
134 string[item->len] = 0; |
|
135 return string; |
|
136 } |
|
137 |
|
138 static SECStatus |
|
139 secu_PrintUserNoticeQualifier(FILE *out, SECItem * qualifierValue, |
|
140 char *msg, int level) |
|
141 { |
|
142 CERTUserNotice *userNotice = NULL; |
|
143 if (qualifierValue) |
|
144 userNotice = CERT_DecodeUserNotice(qualifierValue); |
|
145 if (userNotice) { |
|
146 if (userNotice->noticeReference.organization.len != 0) { |
|
147 char *string = |
|
148 itemToString(&userNotice->noticeReference.organization); |
|
149 SECItem **itemList = userNotice->noticeReference.noticeNumbers; |
|
150 |
|
151 while (itemList && *itemList) { |
|
152 SECU_PrintInteger(out,*itemList,string,level+1); |
|
153 itemList++; |
|
154 } |
|
155 PORT_Free(string); |
|
156 } |
|
157 if (userNotice->displayText.len != 0) { |
|
158 SECU_PrintString(out,&userNotice->displayText, |
|
159 "Display Text", level+1); |
|
160 } |
|
161 CERT_DestroyUserNotice(userNotice); |
|
162 return SECSuccess; |
|
163 } |
|
164 return SECFailure; /* caller will print this value */ |
|
165 } |
|
166 |
|
167 static SECStatus |
|
168 secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier, |
|
169 char *msg,int level) |
|
170 { |
|
171 SECStatus rv; |
|
172 SECItem * qualifierValue = &policyQualifier->qualifierValue; |
|
173 |
|
174 SECU_PrintObjectID(out, &policyQualifier->qualifierID , |
|
175 "Policy Qualifier Name", level); |
|
176 if (!qualifierValue->data) { |
|
177 SECU_Indent(out, level); |
|
178 fprintf(out,"Error: missing qualifier\n"); |
|
179 } else |
|
180 switch (policyQualifier->oid) { |
|
181 case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: |
|
182 rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level); |
|
183 if (SECSuccess == rv) |
|
184 break; |
|
185 /* fall through on error */ |
|
186 case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: |
|
187 default: |
|
188 SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level); |
|
189 break; |
|
190 } |
|
191 return SECSuccess; |
|
192 } |
|
193 |
|
194 static SECStatus |
|
195 secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level) |
|
196 { |
|
197 CERTPolicyQualifier **policyQualifiers; |
|
198 |
|
199 policyQualifiers = policyInfo->policyQualifiers; |
|
200 SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); |
|
201 |
|
202 while (policyQualifiers && *policyQualifiers != NULL) { |
|
203 secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); |
|
204 policyQualifiers++; |
|
205 } |
|
206 return SECSuccess; |
|
207 } |
|
208 |
|
209 void |
|
210 SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) |
|
211 { |
|
212 CERTCertificatePolicies *policies = NULL; |
|
213 CERTPolicyInfo **policyInfos; |
|
214 |
|
215 if (msg) { |
|
216 SECU_Indent(out, level); |
|
217 fprintf(out,"%s: \n",msg); |
|
218 level++; |
|
219 } |
|
220 policies = secu_DecodeCertificatePoliciesExtension(value); |
|
221 if (policies == NULL) { |
|
222 SECU_PrintAny(out, value, "Invalid Policy Data", level); |
|
223 return; |
|
224 } |
|
225 |
|
226 policyInfos = policies->policyInfos; |
|
227 while (policyInfos && *policyInfos != NULL) { |
|
228 secu_PrintPolicyInfo(out,*policyInfos,"",level); |
|
229 policyInfos++; |
|
230 } |
|
231 |
|
232 CERT_DestroyCertificatePoliciesExtension(policies); |
|
233 } |
|
234 |
|
235 |
|
236 void |
|
237 SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, |
|
238 char *msg, int level) |
|
239 { |
|
240 CERTPrivKeyUsagePeriod * prd; |
|
241 PLArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
242 |
|
243 if ( !arena ) { |
|
244 goto loser; |
|
245 } |
|
246 prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value); |
|
247 if (!prd) { |
|
248 goto loser; |
|
249 } |
|
250 if (prd->notBefore.data) { |
|
251 SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level); |
|
252 } |
|
253 if (prd->notAfter.data) { |
|
254 SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level); |
|
255 } |
|
256 if (!prd->notBefore.data && !prd->notAfter.data) { |
|
257 SECU_Indent(out, level); |
|
258 fprintf(out, "Error: notBefore or notAfter MUST be present.\n"); |
|
259 loser: |
|
260 SECU_PrintAny(out, value, msg, level); |
|
261 } |
|
262 if (arena) { |
|
263 PORT_FreeArena(arena, PR_FALSE); |
|
264 } |
|
265 } |