Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
5 /*
6 * Support for various policy related extensions
7 */
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"
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 */
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 };
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 };
52 static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = {
53 { SEC_ASN1_SEQUENCE_OF,
54 offsetof(CERTCertificatePolicies, policyInfos),
55 secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
56 };
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;
69 /* make a new arena */
70 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
72 if ( !arena ) {
73 goto loser;
74 }
76 /* allocate the certifiate policies structure */
77 policies = PORT_ArenaZNew(arena, CERTCertificatePolicies);
78 if ( policies == NULL ) {
79 goto loser;
80 }
82 policies->arena = arena;
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 }
91 /* decode the policy info */
92 rv = SEC_QuickDERDecodeItem(arena, policies,
93 secu_CertificatePoliciesTemplate,
94 &newExtnValue);
96 if ( rv != SECSuccess ) {
97 goto loser;
98 }
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 }
115 return(policies);
117 loser:
118 if ( arena != NULL ) {
119 PORT_FreeArena(arena, PR_FALSE);
120 }
122 return(NULL);
123 }
126 static char *
127 itemToString(SECItem *item)
128 {
129 char *string;
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 }
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;
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 }
167 static SECStatus
168 secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier,
169 char *msg,int level)
170 {
171 SECStatus rv;
172 SECItem * qualifierValue = &policyQualifier->qualifierValue;
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 }
194 static SECStatus
195 secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level)
196 {
197 CERTPolicyQualifier **policyQualifiers;
199 policyQualifiers = policyInfo->policyQualifiers;
200 SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level);
202 while (policyQualifiers && *policyQualifiers != NULL) {
203 secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1);
204 policyQualifiers++;
205 }
206 return SECSuccess;
207 }
209 void
210 SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level)
211 {
212 CERTCertificatePolicies *policies = NULL;
213 CERTPolicyInfo **policyInfos;
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 }
226 policyInfos = policies->policyInfos;
227 while (policyInfos && *policyInfos != NULL) {
228 secu_PrintPolicyInfo(out,*policyInfos,"",level);
229 policyInfos++;
230 }
232 CERT_DestroyCertificatePoliciesExtension(policies);
233 }
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);
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 }