1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pkcs7/certread.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,543 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "cert.h" 1.9 +#include "base64.h" 1.10 +#include "secitem.h" 1.11 +#include "secder.h" 1.12 +#include "secasn1.h" 1.13 +#include "secoid.h" 1.14 +#include "secerr.h" 1.15 + 1.16 +SEC_ASN1_MKSUB(SEC_AnyTemplate) 1.17 +SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate) 1.18 + 1.19 +typedef struct ContentInfoStr ContentInfo; 1.20 +typedef struct DegenerateSignedDataStr DegenerateSignedData; 1.21 + 1.22 +struct ContentInfoStr { 1.23 + SECOidTag contentTypeTag; /* local; not part of encoding */ 1.24 + SECItem contentType; 1.25 + union { 1.26 + SECItem *data; 1.27 + DegenerateSignedData *signedData; 1.28 + } content; 1.29 +}; 1.30 + 1.31 +struct DegenerateSignedDataStr { 1.32 + SECItem version; 1.33 + SECItem **digestAlgorithms; 1.34 + ContentInfo contentInfo; 1.35 + SECItem **certificates; 1.36 + SECItem **crls; 1.37 + SECItem **signerInfos; 1.38 +}; 1.39 + 1.40 +static const SEC_ASN1Template * 1.41 +choose_content_template(void *src_or_dest, PRBool encoding); 1.42 + 1.43 +static const SEC_ASN1TemplateChooserPtr template_chooser 1.44 + = choose_content_template; 1.45 + 1.46 +static const SEC_ASN1Template ContentInfoTemplate[] = { 1.47 + { SEC_ASN1_SEQUENCE, 1.48 + 0, NULL, sizeof(ContentInfo) }, 1.49 + { SEC_ASN1_OBJECT_ID, 1.50 + offsetof(ContentInfo,contentType) }, 1.51 + { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | 1.52 + SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 1.53 + offsetof(ContentInfo,content), 1.54 + &template_chooser }, 1.55 + { 0 } 1.56 +}; 1.57 + 1.58 +static const SEC_ASN1Template DegenerateSignedDataTemplate[] = { 1.59 + { SEC_ASN1_SEQUENCE, 1.60 + 0, NULL, sizeof(DegenerateSignedData) }, 1.61 + { SEC_ASN1_INTEGER, 1.62 + offsetof(DegenerateSignedData,version) }, 1.63 + { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, 1.64 + offsetof(DegenerateSignedData,digestAlgorithms), 1.65 + SEC_ASN1_SUB(SEC_AnyTemplate) }, 1.66 + { SEC_ASN1_INLINE, 1.67 + offsetof(DegenerateSignedData,contentInfo), 1.68 + ContentInfoTemplate }, 1.69 + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1.70 + SEC_ASN1_XTRN | 0, 1.71 + offsetof(DegenerateSignedData,certificates), 1.72 + SEC_ASN1_SUB(SEC_SetOfAnyTemplate) }, 1.73 + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1.74 + SEC_ASN1_XTRN | 1, 1.75 + offsetof(DegenerateSignedData,crls), 1.76 + SEC_ASN1_SUB(SEC_SetOfAnyTemplate) }, 1.77 + { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, 1.78 + offsetof(DegenerateSignedData,signerInfos), 1.79 + SEC_ASN1_SUB(SEC_AnyTemplate) }, 1.80 + { 0 } 1.81 +}; 1.82 + 1.83 +static const SEC_ASN1Template PointerToDegenerateSignedDataTemplate[] = { 1.84 + { SEC_ASN1_POINTER, 0, DegenerateSignedDataTemplate } 1.85 +}; 1.86 + 1.87 +static SECOidTag 1.88 +GetContentTypeTag(ContentInfo *cinfo) 1.89 +{ 1.90 + if (cinfo->contentTypeTag == SEC_OID_UNKNOWN) 1.91 + cinfo->contentTypeTag = SECOID_FindOIDTag(&cinfo->contentType); 1.92 + return cinfo->contentTypeTag; 1.93 +} 1.94 + 1.95 +static const SEC_ASN1Template * 1.96 +choose_content_template(void *src_or_dest, PRBool encoding) 1.97 +{ 1.98 + const SEC_ASN1Template *theTemplate; 1.99 + ContentInfo *cinfo; 1.100 + SECOidTag kind; 1.101 + 1.102 + PORT_Assert(src_or_dest != NULL); 1.103 + if (src_or_dest == NULL) 1.104 + return NULL; 1.105 + 1.106 + cinfo = (ContentInfo*)src_or_dest; 1.107 + kind = GetContentTypeTag(cinfo); 1.108 + switch (kind) { 1.109 + default: 1.110 + theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); 1.111 + break; 1.112 + case SEC_OID_PKCS7_DATA: 1.113 + theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate); 1.114 + break; 1.115 + case SEC_OID_PKCS7_SIGNED_DATA: 1.116 + theTemplate = PointerToDegenerateSignedDataTemplate; 1.117 + break; 1.118 + } 1.119 + return theTemplate; 1.120 +} 1.121 + 1.122 +static SECStatus 1.123 +SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg) 1.124 +{ 1.125 + ContentInfo contentInfo; 1.126 + SECStatus rv; 1.127 + SECItem **certs; 1.128 + int count; 1.129 + PLArenaPool *arena; 1.130 + 1.131 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.132 + if ( arena == NULL ) { 1.133 + return SECFailure; 1.134 + } 1.135 + 1.136 + PORT_Memset(&contentInfo, 0, sizeof(contentInfo)); 1.137 + rv = SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate, 1.138 + pkcs7Item); 1.139 + if ( rv != SECSuccess ) { 1.140 + goto loser; 1.141 + } 1.142 + 1.143 + if ( GetContentTypeTag(&contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) { 1.144 + goto loser; 1.145 + } 1.146 + 1.147 + certs = contentInfo.content.signedData->certificates; 1.148 + if ( certs ) { 1.149 + count = 0; 1.150 + 1.151 + while ( *certs ) { 1.152 + count++; 1.153 + certs++; 1.154 + } 1.155 + rv = (* f)(arg, contentInfo.content.signedData->certificates, count); 1.156 + } 1.157 + 1.158 + rv = SECSuccess; 1.159 + 1.160 + goto done; 1.161 +loser: 1.162 + rv = SECFailure; 1.163 + 1.164 +done: 1.165 + if ( arena ) { 1.166 + PORT_FreeArena(arena, PR_FALSE); 1.167 + } 1.168 + 1.169 + return(rv); 1.170 +} 1.171 + 1.172 +const SEC_ASN1Template SEC_CertSequenceTemplate[] = { 1.173 + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) } 1.174 +}; 1.175 + 1.176 +static SECStatus 1.177 +SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg) 1.178 +{ 1.179 + SECStatus rv; 1.180 + SECItem **certs; 1.181 + int count; 1.182 + SECItem **rawCerts = NULL; 1.183 + PLArenaPool *arena; 1.184 + ContentInfo contentInfo; 1.185 + 1.186 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.187 + if ( arena == NULL ) { 1.188 + return SECFailure; 1.189 + } 1.190 + 1.191 + PORT_Memset(&contentInfo, 0, sizeof(contentInfo)); 1.192 + rv = SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate, 1.193 + certsItem); 1.194 + if ( rv != SECSuccess ) { 1.195 + goto loser; 1.196 + } 1.197 + 1.198 + if ( GetContentTypeTag(&contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) { 1.199 + goto loser; 1.200 + } 1.201 + 1.202 + rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate, 1.203 + contentInfo.content.data); 1.204 + 1.205 + if (rv != SECSuccess) { 1.206 + goto loser; 1.207 + } 1.208 + 1.209 + certs = rawCerts; 1.210 + if ( certs ) { 1.211 + count = 0; 1.212 + 1.213 + while ( *certs ) { 1.214 + count++; 1.215 + certs++; 1.216 + } 1.217 + rv = (* f)(arg, rawCerts, count); 1.218 + } 1.219 + 1.220 + rv = SECSuccess; 1.221 + 1.222 + goto done; 1.223 +loser: 1.224 + rv = SECFailure; 1.225 + 1.226 +done: 1.227 + if ( arena ) { 1.228 + PORT_FreeArena(arena, PR_FALSE); 1.229 + } 1.230 + 1.231 + return(rv); 1.232 +} 1.233 + 1.234 +CERTCertificate * 1.235 +CERT_ConvertAndDecodeCertificate(char *certstr) 1.236 +{ 1.237 + CERTCertificate *cert; 1.238 + SECStatus rv; 1.239 + SECItem der; 1.240 + 1.241 + rv = ATOB_ConvertAsciiToItem(&der, certstr); 1.242 + if (rv != SECSuccess) 1.243 + return NULL; 1.244 + 1.245 + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 1.246 + &der, NULL, PR_FALSE, PR_TRUE); 1.247 + 1.248 + PORT_Free(der.data); 1.249 + return cert; 1.250 +} 1.251 + 1.252 +static const char NS_CERT_HEADER[] = "-----BEGIN CERTIFICATE-----"; 1.253 +static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----"; 1.254 +#define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1) 1.255 +#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1) 1.256 + 1.257 +/* 1.258 + * read an old style ascii or binary certificate chain 1.259 + */ 1.260 +SECStatus 1.261 +CERT_DecodeCertPackage(char *certbuf, 1.262 + int certlen, 1.263 + CERTImportCertificateFunc f, 1.264 + void *arg) 1.265 +{ 1.266 + unsigned char *cp; 1.267 + unsigned char *bincert = NULL; 1.268 + char * ascCert = NULL; 1.269 + SECStatus rv; 1.270 + 1.271 + if ( certbuf == NULL ) { 1.272 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.273 + return(SECFailure); 1.274 + } 1.275 + /* 1.276 + * Make sure certlen is long enough to handle the longest possible 1.277 + * reference in the code below: 1.278 + * 0x30 0x84 l1 l2 l3 l4 + 1.279 + * tag 9 o1 o2 o3 o4 o5 o6 o7 o8 o9 1.280 + * where 9 is the longest length of the expected oids we are testing. 1.281 + * 6 + 11 = 17. 17 bytes is clearly too small to code any kind of 1.282 + * certificate (a 128 bit ECC certificate contains at least an 8 byte 1.283 + * key and a 16 byte signature, plus coding overhead). Typically a cert 1.284 + * is much larger. So it's safe to require certlen to be at least 17 1.285 + * bytes. 1.286 + */ 1.287 + if (certlen < 17) { 1.288 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.289 + return(SECFailure); 1.290 + } 1.291 + 1.292 + cp = (unsigned char *)certbuf; 1.293 + 1.294 + /* is a DER encoded certificate of some type? */ 1.295 + if ( ( *cp & 0x1f ) == SEC_ASN1_SEQUENCE ) { 1.296 + SECItem certitem; 1.297 + SECItem *pcertitem = &certitem; 1.298 + int seqLen, seqLenLen; 1.299 + 1.300 + cp++; 1.301 + 1.302 + if ( *cp & 0x80) { 1.303 + /* Multibyte length */ 1.304 + seqLenLen = cp[0] & 0x7f; 1.305 + 1.306 + switch (seqLenLen) { 1.307 + case 4: 1.308 + seqLen = ((unsigned long)cp[1]<<24) | 1.309 + ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4]; 1.310 + break; 1.311 + case 3: 1.312 + seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3]; 1.313 + break; 1.314 + case 2: 1.315 + seqLen = (cp[1]<<8) | cp[2]; 1.316 + break; 1.317 + case 1: 1.318 + seqLen = cp[1]; 1.319 + break; 1.320 + case 0: 1.321 + /* indefinite length */ 1.322 + seqLen = 0; 1.323 + break; 1.324 + default: 1.325 + goto notder; 1.326 + } 1.327 + cp += ( seqLenLen + 1 ); 1.328 + 1.329 + } else { 1.330 + seqLenLen = 0; 1.331 + seqLen = *cp; 1.332 + cp++; 1.333 + } 1.334 + 1.335 + /* check entire length if definite length */ 1.336 + if ( seqLen || seqLenLen ) { 1.337 + if ( certlen != ( seqLen + seqLenLen + 2 ) ) { 1.338 + if (certlen > ( seqLen + seqLenLen + 2 )) 1.339 + PORT_SetError(SEC_ERROR_EXTRA_INPUT); 1.340 + else 1.341 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.342 + goto notder; 1.343 + } 1.344 + } 1.345 + 1.346 + /* check the type oid */ 1.347 + if ( cp[0] == SEC_ASN1_OBJECT_ID ) { 1.348 + SECOidData *oiddata; 1.349 + SECItem oiditem; 1.350 + /* XXX - assume DER encoding of OID len!! */ 1.351 + oiditem.len = cp[1]; 1.352 + /* if we add an oid below that is longer than 9 bytes, then we 1.353 + * need to change the certlen check at the top of the function 1.354 + * to prevent a buffer overflow 1.355 + */ 1.356 + if ( oiditem.len > 9 ) { 1.357 + PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID); 1.358 + return(SECFailure); 1.359 + } 1.360 + oiditem.data = (unsigned char *)&cp[2]; 1.361 + oiddata = SECOID_FindOID(&oiditem); 1.362 + if ( oiddata == NULL ) { 1.363 + return(SECFailure); 1.364 + } 1.365 + 1.366 + certitem.data = (unsigned char*)certbuf; 1.367 + certitem.len = certlen; 1.368 + 1.369 + switch ( oiddata->offset ) { 1.370 + case SEC_OID_PKCS7_SIGNED_DATA: 1.371 + /* oid: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 */ 1.372 + return(SEC_ReadPKCS7Certs(&certitem, f, arg)); 1.373 + break; 1.374 + case SEC_OID_NS_TYPE_CERT_SEQUENCE: 1.375 + /* oid: 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05 */ 1.376 + return(SEC_ReadCertSequence(&certitem, f, arg)); 1.377 + break; 1.378 + default: 1.379 + break; 1.380 + } 1.381 + 1.382 + } else { 1.383 + /* it had better be a certificate by now!! */ 1.384 + certitem.data = (unsigned char*)certbuf; 1.385 + certitem.len = certlen; 1.386 + 1.387 + rv = (* f)(arg, &pcertitem, 1); 1.388 + return(rv); 1.389 + } 1.390 + } 1.391 + 1.392 + /* now look for a netscape base64 ascii encoded cert */ 1.393 +notder: 1.394 + { 1.395 + unsigned char *certbegin = NULL; 1.396 + unsigned char *certend = NULL; 1.397 + char *pc; 1.398 + int cl; 1.399 + 1.400 + /* Convert the ASCII data into a nul-terminated string */ 1.401 + ascCert = (char *)PORT_Alloc(certlen + 1); 1.402 + if (!ascCert) { 1.403 + rv = SECFailure; 1.404 + goto loser; 1.405 + } 1.406 + 1.407 + PORT_Memcpy(ascCert, certbuf, certlen); 1.408 + ascCert[certlen] = '\0'; 1.409 + 1.410 + pc = PORT_Strchr(ascCert, '\n'); /* find an EOL */ 1.411 + if (!pc) { /* maybe this is a MAC file */ 1.412 + pc = ascCert; 1.413 + while (*pc && NULL != (pc = PORT_Strchr(pc, '\r'))) { 1.414 + *pc++ = '\n'; 1.415 + } 1.416 + } 1.417 + 1.418 + cp = (unsigned char *)ascCert; 1.419 + cl = certlen; 1.420 + 1.421 + /* find the beginning marker */ 1.422 + while ( cl > NS_CERT_HEADER_LEN ) { 1.423 + int found = 0; 1.424 + if ( !PORT_Strncasecmp((char *)cp, NS_CERT_HEADER, 1.425 + NS_CERT_HEADER_LEN) ) { 1.426 + cl -= NS_CERT_HEADER_LEN; 1.427 + cp += NS_CERT_HEADER_LEN; 1.428 + found = 1; 1.429 + } 1.430 + 1.431 + /* skip to next eol */ 1.432 + while ( cl && ( *cp != '\n' )) { 1.433 + cp++; 1.434 + cl--; 1.435 + } 1.436 + 1.437 + /* skip all blank lines */ 1.438 + while ( cl && ( *cp == '\n' || *cp == '\r' )) { 1.439 + cp++; 1.440 + cl--; 1.441 + } 1.442 + if (cl && found) { 1.443 + certbegin = cp; 1.444 + break; 1.445 + } 1.446 + } 1.447 + 1.448 + if ( certbegin ) { 1.449 + /* find the ending marker */ 1.450 + while ( cl >= NS_CERT_TRAILER_LEN ) { 1.451 + if ( !PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER, 1.452 + NS_CERT_TRAILER_LEN) ) { 1.453 + certend = cp; 1.454 + break; 1.455 + } 1.456 + 1.457 + /* skip to next eol */ 1.458 + while ( cl && ( *cp != '\n' )) { 1.459 + cp++; 1.460 + cl--; 1.461 + } 1.462 + 1.463 + /* skip all blank lines */ 1.464 + while ( cl && ( *cp == '\n' || *cp == '\r' )) { 1.465 + cp++; 1.466 + cl--; 1.467 + } 1.468 + } 1.469 + } 1.470 + 1.471 + if ( certbegin && certend ) { 1.472 + unsigned int binLen; 1.473 + 1.474 + *certend = 0; 1.475 + /* convert to binary */ 1.476 + bincert = ATOB_AsciiToData((char *)certbegin, &binLen); 1.477 + if (!bincert) { 1.478 + rv = SECFailure; 1.479 + goto loser; 1.480 + } 1.481 + 1.482 + /* now recurse to decode the binary */ 1.483 + rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg); 1.484 + 1.485 + } else { 1.486 + PORT_SetError(SEC_ERROR_BAD_DER); 1.487 + rv = SECFailure; 1.488 + } 1.489 + } 1.490 + 1.491 +loser: 1.492 + 1.493 + if ( bincert ) { 1.494 + PORT_Free(bincert); 1.495 + } 1.496 + 1.497 + if ( ascCert ) { 1.498 + PORT_Free(ascCert); 1.499 + } 1.500 + 1.501 + return(rv); 1.502 +} 1.503 + 1.504 +typedef struct { 1.505 + PLArenaPool *arena; 1.506 + SECItem cert; 1.507 +} collect_args; 1.508 + 1.509 +static SECStatus 1.510 +collect_certs(void *arg, SECItem **certs, int numcerts) 1.511 +{ 1.512 + SECStatus rv; 1.513 + collect_args *collectArgs; 1.514 + 1.515 + collectArgs = (collect_args *)arg; 1.516 + 1.517 + rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs); 1.518 + 1.519 + return(rv); 1.520 +} 1.521 + 1.522 + 1.523 +/* 1.524 + * read an old style ascii or binary certificate 1.525 + */ 1.526 +CERTCertificate * 1.527 +CERT_DecodeCertFromPackage(char *certbuf, int certlen) 1.528 +{ 1.529 + collect_args collectArgs; 1.530 + SECStatus rv; 1.531 + CERTCertificate *cert = NULL; 1.532 + 1.533 + collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.534 + 1.535 + rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs, 1.536 + (void *)&collectArgs); 1.537 + if ( rv == SECSuccess ) { 1.538 + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 1.539 + &collectArgs.cert, NULL, 1.540 + PR_FALSE, PR_TRUE); 1.541 + } 1.542 + 1.543 + PORT_FreeArena(collectArgs.arena, PR_FALSE); 1.544 + 1.545 + return(cert); 1.546 +}