certv3.c (5737B)
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 * Code for dealing with X509.V3 extensions. 7 */ 8 9 #include "cert.h" 10 #include "secitem.h" 11 #include "secoid.h" 12 #include "secder.h" 13 #include "secasn1.h" 14 #include "certxutl.h" 15 #include "secerr.h" 16 17 SECStatus 18 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, SECItem *value) 19 { 20 return (cert_FindExtensionByOID(cert->extensions, oid, value)); 21 } 22 23 SECStatus 24 CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value) 25 { 26 return (cert_FindExtension(cert->extensions, tag, value)); 27 } 28 29 static void 30 SetExts(void *object, CERTCertExtension **exts) 31 { 32 CERTCertificate *cert = (CERTCertificate *)object; 33 34 cert->extensions = exts; 35 DER_SetUInteger(cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3); 36 } 37 38 void * 39 CERT_StartCertExtensions(CERTCertificate *cert) 40 { 41 return (cert_StartExtensions((void *)cert, cert->arena, SetExts)); 42 } 43 44 /* 45 * get the value of the Netscape Certificate Type Extension 46 */ 47 SECStatus 48 CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem) 49 { 50 51 return (CERT_FindBitStringExtension( 52 cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem)); 53 } 54 55 /* 56 * get the value of a string type extension 57 */ 58 char * 59 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag) 60 { 61 SECItem wrapperItem, tmpItem = { siBuffer, 0 }; 62 SECStatus rv; 63 PLArenaPool *arena = NULL; 64 char *retstring = NULL; 65 66 wrapperItem.data = NULL; 67 tmpItem.data = NULL; 68 69 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 70 71 if (!arena) { 72 goto loser; 73 } 74 75 rv = cert_FindExtension(cert->extensions, oidtag, &wrapperItem); 76 if (rv != SECSuccess) { 77 goto loser; 78 } 79 80 rv = SEC_QuickDERDecodeItem( 81 arena, &tmpItem, SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem); 82 83 if (rv != SECSuccess) { 84 goto loser; 85 } 86 87 retstring = (char *)PORT_Alloc(tmpItem.len + 1); 88 if (retstring == NULL) { 89 goto loser; 90 } 91 92 PORT_Memcpy(retstring, tmpItem.data, tmpItem.len); 93 retstring[tmpItem.len] = '\0'; 94 95 loser: 96 if (arena) { 97 PORT_FreeArena(arena, PR_FALSE); 98 } 99 100 if (wrapperItem.data) { 101 PORT_Free(wrapperItem.data); 102 } 103 104 return (retstring); 105 } 106 107 /* 108 * get the value of the X.509 v3 Key Usage Extension 109 */ 110 SECStatus 111 CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem) 112 { 113 114 return (CERT_FindBitStringExtension(cert->extensions, 115 SEC_OID_X509_KEY_USAGE, retItem)); 116 } 117 118 /* 119 * get the value of the X.509 v3 Key Usage Extension 120 */ 121 SECStatus 122 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem) 123 { 124 125 SECStatus rv; 126 SECItem encodedValue = { siBuffer, NULL, 0 }; 127 SECItem decodedValue = { siBuffer, NULL, 0 }; 128 129 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, 130 &encodedValue); 131 if (rv == SECSuccess) { 132 PORTCheapArenaPool tmpArena; 133 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 134 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodedValue, 135 SEC_ASN1_GET(SEC_OctetStringTemplate), 136 &encodedValue); 137 if (rv == SECSuccess) { 138 rv = SECITEM_CopyItem(NULL, retItem, &decodedValue); 139 } 140 PORT_DestroyCheapArena(&tmpArena); 141 } 142 SECITEM_FreeItem(&encodedValue, PR_FALSE); 143 return rv; 144 } 145 146 SECStatus 147 CERT_FindBasicConstraintExten(CERTCertificate *cert, 148 CERTBasicConstraints *value) 149 { 150 SECItem encodedExtenValue; 151 SECStatus rv; 152 153 encodedExtenValue.data = NULL; 154 encodedExtenValue.len = 0; 155 156 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS, 157 &encodedExtenValue); 158 if (rv != SECSuccess) { 159 return (rv); 160 } 161 162 rv = CERT_DecodeBasicConstraintValue(value, &encodedExtenValue); 163 164 /* free the raw extension data */ 165 PORT_Free(encodedExtenValue.data); 166 encodedExtenValue.data = NULL; 167 168 return (rv); 169 } 170 171 CERTAuthKeyID * 172 CERT_FindAuthKeyIDExten(PLArenaPool *arena, CERTCertificate *cert) 173 { 174 SECItem encodedExtenValue; 175 SECStatus rv; 176 CERTAuthKeyID *ret; 177 178 encodedExtenValue.data = NULL; 179 encodedExtenValue.len = 0; 180 181 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID, 182 &encodedExtenValue); 183 if (rv != SECSuccess) { 184 return (NULL); 185 } 186 187 ret = CERT_DecodeAuthKeyID(arena, &encodedExtenValue); 188 189 PORT_Free(encodedExtenValue.data); 190 encodedExtenValue.data = NULL; 191 192 return (ret); 193 } 194 195 SECStatus 196 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage) 197 { 198 SECItem keyUsage; 199 SECStatus rv; 200 201 /* There is no extension, v1 or v2 certificate */ 202 if (cert->extensions == NULL) { 203 return (SECSuccess); 204 } 205 206 keyUsage.data = NULL; 207 208 /* This code formerly ignored the Key Usage extension if it was 209 ** marked non-critical. That was wrong. Since we do understand it, 210 ** we are obligated to honor it, whether or not it is critical. 211 */ 212 rv = CERT_FindKeyUsageExtension(cert, &keyUsage); 213 if (rv == SECFailure) { 214 rv = (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) ? SECSuccess 215 : SECFailure; 216 } else if (!keyUsage.data || !keyUsage.len || !(keyUsage.data[0] & usage)) { 217 PORT_SetError(SEC_ERROR_CERT_USAGES_INVALID); 218 rv = SECFailure; 219 } 220 PORT_Free(keyUsage.data); 221 return (rv); 222 }