X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb..d87e115847b84cc1c3a1ef198a20181cd85b5309:/Security/libsecurity_ocspd/common/ocspdUtils.cpp diff --git a/Security/libsecurity_ocspd/common/ocspdUtils.cpp b/Security/libsecurity_ocspd/common/ocspdUtils.cpp index cee4b180..efbdb8a6 100644 --- a/Security/libsecurity_ocspd/common/ocspdUtils.cpp +++ b/Security/libsecurity_ocspd/common/ocspdUtils.cpp @@ -2,14 +2,14 @@ * Copyright (c) 2000,2002,2011-2012,2014 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,15 +17,18 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ -/* +/* * ocspUtils.cpp - common utilities for OCSPD */ #include "ocspdUtils.h" +#include "ocspdDebug.h" +#include +#include #include /* @@ -34,8 +37,8 @@ CSSM_BOOL ocspdCompareCssmData( const CSSM_DATA *data1, const CSSM_DATA *data2) -{ - if((data1 == NULL) || (data1->Data == NULL) || +{ + if((data1 == NULL) || (data1->Data == NULL) || (data2 == NULL) || (data2->Data == NULL) || (data1->Length != data2->Length)) { return CSSM_FALSE; @@ -53,8 +56,8 @@ CSSM_BOOL ocspdCompareCssmData( /* * Convert a generalized time string, with a 4-digit year and no trailing - * fractional seconds or time zone info, to a CFAbsoluteTime. Returns - * NULL_TIME (0.0) on error. + * fractional seconds or time zone info, to a CFAbsoluteTime. Returns + * NULL_TIME (0.0) on error. */ static CFAbsoluteTime parseGenTime( const uint8 *str, @@ -63,7 +66,7 @@ static CFAbsoluteTime parseGenTime( if((str == NULL) || (len == 0)) { return NULL_TIME; } - + /* tolerate NULL terminated or not */ if(str[len - 1] == '\0') { len--; @@ -75,7 +78,7 @@ static CFAbsoluteTime parseGenTime( CFGregorianDate greg; memset(&greg, 0, sizeof(greg)); const uint8 *cp = str; - + /* YEAR */ szTemp[0] = *cp++; szTemp[1] = *cp++; @@ -84,7 +87,7 @@ static CFAbsoluteTime parseGenTime( szTemp[4] = '\0'; len -= 4; greg.year = atoi(szTemp); - + /* MONTH - CFGregorianDate ranges 1..12, just like the string */ if(len < 2) { return NULL_TIME; @@ -104,7 +107,7 @@ static CFAbsoluteTime parseGenTime( szTemp[2] = '\0'; greg.day = atoi( szTemp ); len -= 2; - + if(len >= 2) { /* HOUR 0..23 */ szTemp[0] = *cp++; @@ -134,7 +137,7 @@ static CFAbsoluteTime parseGenTime( /* * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL on parse error. - * Fractional parts of a second are discarded. + * Fractional parts of a second are discarded. */ CFAbsoluteTime genTimeToCFAbsTime( const CSSM_DATA *strData) @@ -142,20 +145,20 @@ CFAbsoluteTime genTimeToCFAbsTime( if((strData == NULL) || (strData->Data == NULL) || (strData->Length == 0)) { return NULL_TIME; } - + uint8 *timeStr = strData->Data; size_t timeStrLen = strData->Length; - + /* tolerate NULL terminated or not */ if(timeStr[timeStrLen - 1] == '\0') { timeStrLen--; } - + /* start with a fresh editable copy */ uint8 *str = (uint8 *)malloc(timeStrLen); uint32 strLen = 0; - - /* + + /* * If there is a decimal point, strip it and all trailing digits off */ const uint8 *inCp = timeStr; @@ -166,7 +169,7 @@ CFAbsoluteTime genTimeToCFAbsTime( bool minusOffset = false; bool isGMT = false; size_t toGo = timeStrLen; - + do { if(*inCp == '.') { if(foundDecimal) { @@ -176,7 +179,7 @@ CFAbsoluteTime genTimeToCFAbsTime( } } foundDecimal++; - + /* skip the decimal point... */ inCp++; toGo--; @@ -213,19 +216,19 @@ CFAbsoluteTime genTimeToCFAbsTime( toGo--; } } while(toGo != 0); - + if(str[strLen - 1] == 'Z') { isGMT = true; strLen--; } - + CFAbsoluteTime absTime; absTime = parseGenTime(str, strLen); free(str); if(absTime == NULL_TIME) { return NULL_TIME; } - + /* post processing needed? */ if(isGMT) { /* Nope, string was in GMT */ @@ -253,7 +256,7 @@ CFAbsoluteTime genTimeToCFAbsTime( return absTime; } -/* +/* * Convert CFAbsoluteTime to generalized time string, GMT format (4 digit year, * trailing 'Z'). Caller allocated the output which is GENERAL_TIME_STRLEN+1 bytes. */ @@ -266,10 +269,10 @@ void cfAbsTimeToGgenTime( CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(absTime, tz); int seconds = (int)greg.second; sprintf(genTime, "%04d%02d%02d%02d%02d%02dZ", - (int)greg.year, greg.month, greg.day, greg.hour, + (int)greg.year, greg.month, greg.day, greg.hour, greg.minute, seconds); } - + void ocspdSha1( const void *data, CC_LONG len, @@ -328,3 +331,87 @@ unsigned ocspdArraySize( } return count; } + +/* Fill out a CSSM_DATA with the subset of public key bytes from the given + * CSSM_KEY_PTR which should be hashed to produce the issuerKeyHash field + * of a CertID in an OCSP request. + * + * For RSA keys, this simply copies the input key pointer and length. + * For EC keys, we need to further deconstruct the SubjectPublicKeyInfo + * to obtain the key bytes (i.e. curve point) for hashing. + * + * Returns CSSM_OK on success, or non-zero error if the bytes could not + * be retrieved. + */ +CSSM_RETURN ocspdGetPublicKeyBytes( + SecAsn1CoderRef coder, // optional + CSSM_KEY_PTR publicKey, // input public key + CSSM_DATA &publicKeyBytes) // filled in by this function +{ + CSSM_RETURN crtn = CSSM_OK; + SecAsn1CoderRef _coder = NULL; + + if(publicKey == NULL) { + crtn = CSSMERR_CSP_INVALID_KEY_POINTER; + goto exit; + } + + if(coder == NULL) { + crtn = SecAsn1CoderCreate(&_coder); + if(crtn) { + goto exit; + } + coder = _coder; + } + + publicKeyBytes.Length = publicKey->KeyData.Length; + publicKeyBytes.Data = publicKey->KeyData.Data; + + if(publicKey->KeyHeader.AlgorithmId == CSSM_ALGID_ECDSA) { + /* + * For an EC key, publicKey->KeyData is a SubjectPublicKeyInfo + * ASN.1 sequence that includes the algorithm identifier. + * We only want to return the bit string portion of the key here. + */ + SecAsn1PubKeyInfo pkinfo; + memset(&pkinfo, 0, sizeof(pkinfo)); + if(SecAsn1Decode(coder, + publicKey->KeyData.Data, + publicKey->KeyData.Length, + kSecAsn1SubjectPublicKeyInfoTemplate, + &pkinfo) == 0) { + if(pkinfo.subjectPublicKey.Length && + pkinfo.subjectPublicKey.Data) { + publicKeyBytes.Length = pkinfo.subjectPublicKey.Length >> 3; + publicKeyBytes.Data = pkinfo.subjectPublicKey.Data; + /* + * Important: if we allocated the SecAsn1Coder, the memory + * being pointed to by pkinfo.subjectPublicKey.Data will be + * deallocated when the coder is released below. We want to + * point to the identical data inside the caller's public key, + * now that the decoder has identified it for us. + */ + if(publicKeyBytes.Length <= publicKey->KeyData.Length) { + publicKeyBytes.Data = (uint8*)((uintptr_t)publicKey->KeyData.Data + + (publicKey->KeyData.Length - publicKeyBytes.Length)); + goto exit; + } + /* intentional fallthrough to error exit */ + } + ocspdErrorLog("ocspdGetPublicKeyBytes: invalid SecAsn1PubKeyInfo\n"); + crtn = CSSMERR_CSP_INVALID_KEY_POINTER; + } + else { + /* Unable to decode using kSecAsn1SubjectPublicKeyInfoTemplate. + * This may or may not be an error; just return the unchanged key. + */ + ocspdErrorLog("ocspdGetPublicKeyBytes: unable to decode SubjectPublicKeyInfo\n"); + } + } + +exit: + if(_coder) { + SecAsn1CoderRelease(_coder); + } + return crtn; +}