pppolicy.c (8087B)
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 static CERTCertificatePolicies * 59 secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) 60 { 61 PLArenaPool *arena = NULL; 62 SECStatus rv; 63 CERTCertificatePolicies *policies; 64 CERTPolicyInfo **policyInfos, *policyInfo; 65 CERTPolicyQualifier **policyQualifiers, *policyQualifier; 66 SECItem newExtnValue; 67 68 /* make a new arena */ 69 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 70 71 if (!arena) { 72 goto loser; 73 } 74 75 /* allocate the certifiate policies structure */ 76 policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); 77 if (policies == NULL) { 78 goto loser; 79 } 80 81 policies->arena = arena; 82 83 /* copy the DER into the arena, since Quick DER returns data that points 84 into the DER input, which may get freed by the caller */ 85 rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); 86 if (rv != SECSuccess) { 87 goto loser; 88 } 89 90 /* decode the policy info */ 91 rv = SEC_QuickDERDecodeItem(arena, policies, 92 secu_CertificatePoliciesTemplate, 93 &newExtnValue); 94 95 if (rv != SECSuccess) { 96 goto loser; 97 } 98 99 /* initialize the oid tags */ 100 policyInfos = policies->policyInfos; 101 while (policyInfos != NULL && *policyInfos != NULL) { 102 policyInfo = *policyInfos; 103 policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); 104 policyQualifiers = policyInfo->policyQualifiers; 105 while (policyQualifiers && *policyQualifiers != NULL) { 106 policyQualifier = *policyQualifiers; 107 policyQualifier->oid = 108 SECOID_FindOIDTag(&policyQualifier->qualifierID); 109 policyQualifiers++; 110 } 111 policyInfos++; 112 } 113 114 return (policies); 115 116 loser: 117 if (arena != NULL) { 118 PORT_FreeArena(arena, PR_FALSE); 119 } 120 121 return (NULL); 122 } 123 124 static char * 125 itemToString(SECItem *item) 126 { 127 char *string; 128 129 string = PORT_ZAlloc(item->len + 1); 130 if (string == NULL) 131 return NULL; 132 PORT_Memcpy(string, item->data, item->len); 133 string[item->len] = 0; 134 return string; 135 } 136 137 static SECStatus 138 secu_PrintUserNoticeQualifier(FILE *out, SECItem *qualifierValue, 139 char *msg, int level) 140 { 141 CERTUserNotice *userNotice = NULL; 142 if (qualifierValue) 143 userNotice = CERT_DecodeUserNotice(qualifierValue); 144 if (userNotice) { 145 if (userNotice->noticeReference.organization.len != 0) { 146 char *string = 147 itemToString(&userNotice->noticeReference.organization); 148 SECItem **itemList = userNotice->noticeReference.noticeNumbers; 149 150 while (itemList && *itemList) { 151 SECU_PrintInteger(out, *itemList, string, level + 1); 152 itemList++; 153 } 154 PORT_Free(string); 155 } 156 if (userNotice->displayText.len != 0) { 157 SECU_PrintString(out, &userNotice->displayText, 158 "Display Text", level + 1); 159 } 160 CERT_DestroyUserNotice(userNotice); 161 return SECSuccess; 162 } 163 return SECFailure; /* caller will print this value */ 164 } 165 166 static SECStatus 167 secu_PrintPolicyQualifier(FILE *out, CERTPolicyQualifier *policyQualifier, 168 char *msg, int level) 169 { 170 SECStatus rv; 171 SECItem *qualifierValue = &policyQualifier->qualifierValue; 172 173 SECU_PrintObjectID(out, &policyQualifier->qualifierID, 174 "Policy Qualifier Name", level); 175 if (!qualifierValue->data) { 176 SECU_Indent(out, level); 177 fprintf(out, "Error: missing qualifier\n"); 178 } else 179 switch (policyQualifier->oid) { 180 case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: 181 rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level); 182 if (SECSuccess == rv) 183 break; 184 /* fall through on error */ 185 case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: 186 default: 187 SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level); 188 break; 189 } 190 return SECSuccess; 191 } 192 193 static SECStatus 194 secu_PrintPolicyInfo(FILE *out, CERTPolicyInfo *policyInfo, char *msg, int level) 195 { 196 CERTPolicyQualifier **policyQualifiers; 197 198 policyQualifiers = policyInfo->policyQualifiers; 199 SECU_PrintObjectID(out, &policyInfo->policyID, "Policy Name", level); 200 201 while (policyQualifiers && *policyQualifiers != NULL) { 202 secu_PrintPolicyQualifier(out, *policyQualifiers, "", level + 1); 203 policyQualifiers++; 204 } 205 return SECSuccess; 206 } 207 208 void 209 SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) 210 { 211 CERTCertificatePolicies *policies = NULL; 212 CERTPolicyInfo **policyInfos; 213 214 if (msg) { 215 SECU_Indent(out, level); 216 fprintf(out, "%s: \n", msg); 217 level++; 218 } 219 policies = secu_DecodeCertificatePoliciesExtension(value); 220 if (policies == NULL) { 221 SECU_PrintAny(out, value, "Invalid Policy Data", level); 222 return; 223 } 224 225 policyInfos = policies->policyInfos; 226 while (policyInfos && *policyInfos != NULL) { 227 secu_PrintPolicyInfo(out, *policyInfos, "", level); 228 policyInfos++; 229 } 230 231 CERT_DestroyCertificatePoliciesExtension(policies); 232 } 233 234 void 235 SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, 236 char *msg, int level) 237 { 238 CERTPrivKeyUsagePeriod *prd; 239 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 240 241 if (!arena) { 242 goto loser; 243 } 244 prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value); 245 if (!prd) { 246 goto loser; 247 } 248 if (prd->notBefore.data) { 249 SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level); 250 } 251 if (prd->notAfter.data) { 252 SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level); 253 } 254 if (!prd->notBefore.data && !prd->notAfter.data) { 255 SECU_Indent(out, level); 256 fprintf(out, "Error: notBefore or notAfter MUST be present.\n"); 257 loser: 258 SECU_PrintAny(out, value, msg, level); 259 } 260 if (arena) { 261 PORT_FreeArena(arena, PR_FALSE); 262 } 263 }