1/* 2 * Copyright (c) 2000,2002,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * ocspUtils.cpp - common utilities for OCSPD 26 */ 27 28#include "ocspdUtils.h" 29#include <CoreFoundation/CoreFoundation.h> 30 31/* 32 * Compare two CSSM_DATAs, return CSSM_TRUE if identical. 33 */ 34CSSM_BOOL ocspdCompareCssmData( 35 const CSSM_DATA *data1, 36 const CSSM_DATA *data2) 37{ 38 if((data1 == NULL) || (data1->Data == NULL) || 39 (data2 == NULL) || (data2->Data == NULL) || 40 (data1->Length != data2->Length)) { 41 return CSSM_FALSE; 42 } 43 if(data1->Length != data2->Length) { 44 return CSSM_FALSE; 45 } 46 if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { 47 return CSSM_TRUE; 48 } 49 else { 50 return CSSM_FALSE; 51 } 52} 53 54/* 55 * Convert a generalized time string, with a 4-digit year and no trailing 56 * fractional seconds or time zone info, to a CFAbsoluteTime. Returns 57 * NULL_TIME (0.0) on error. 58 */ 59static CFAbsoluteTime parseGenTime( 60 const uint8 *str, 61 uint32 len) 62{ 63 if((str == NULL) || (len == 0)) { 64 return NULL_TIME; 65 } 66 67 /* tolerate NULL terminated or not */ 68 if(str[len - 1] == '\0') { 69 len--; 70 } 71 if(len < 4) { 72 return NULL_TIME; 73 } 74 char szTemp[5]; 75 CFGregorianDate greg; 76 memset(&greg, 0, sizeof(greg)); 77 const uint8 *cp = str; 78 79 /* YEAR */ 80 szTemp[0] = *cp++; 81 szTemp[1] = *cp++; 82 szTemp[2] = *cp++; 83 szTemp[3] = *cp++; 84 szTemp[4] = '\0'; 85 len -= 4; 86 greg.year = atoi(szTemp); 87 88 /* MONTH - CFGregorianDate ranges 1..12, just like the string */ 89 if(len < 2) { 90 return NULL_TIME; 91 } 92 szTemp[0] = *cp++; 93 szTemp[1] = *cp++; 94 szTemp[2] = '\0'; 95 len -= 2; 96 greg.month = atoi( szTemp ); 97 98 /* DAY - 1..31 */ 99 if(len < 2) { 100 return NULL_TIME; 101 } 102 szTemp[0] = *cp++; 103 szTemp[1] = *cp++; 104 szTemp[2] = '\0'; 105 greg.day = atoi( szTemp ); 106 len -= 2; 107 108 if(len >= 2) { 109 /* HOUR 0..23 */ 110 szTemp[0] = *cp++; 111 szTemp[1] = *cp++; 112 szTemp[2] = '\0'; 113 greg.hour = atoi( szTemp ); 114 len -= 2; 115 } 116 if(len >= 2) { 117 /* MINUTE 0..59 */ 118 szTemp[0] = *cp++; 119 szTemp[1] = *cp++; 120 szTemp[2] = '\0'; 121 greg.minute = atoi( szTemp ); 122 len -= 2; 123 } 124 if(len >= 2) { 125 /* SECOND 0..59 */ 126 szTemp[0] = *cp++; 127 szTemp[1] = *cp++; 128 szTemp[2] = '\0'; 129 greg.second = atoi( szTemp ); 130 len -= 2; 131 } 132 return CFGregorianDateGetAbsoluteTime(greg, NULL); 133} 134 135/* 136 * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL on parse error. 137 * Fractional parts of a second are discarded. 138 */ 139CFAbsoluteTime genTimeToCFAbsTime( 140 const CSSM_DATA *strData) 141{ 142 if((strData == NULL) || (strData->Data == NULL) || (strData->Length == 0)) { 143 return NULL_TIME; 144 } 145 146 uint8 *timeStr = strData->Data; 147 size_t timeStrLen = strData->Length; 148 149 /* tolerate NULL terminated or not */ 150 if(timeStr[timeStrLen - 1] == '\0') { 151 timeStrLen--; 152 } 153 154 /* start with a fresh editable copy */ 155 uint8 *str = (uint8 *)malloc(timeStrLen); 156 uint32 strLen = 0; 157 158 /* 159 * If there is a decimal point, strip it and all trailing digits off 160 */ 161 const uint8 *inCp = timeStr; 162 uint8 *outCp = str; 163 int foundDecimal = 0; 164 int minutesOffset = 0; 165 int hoursOffset = 0; 166 bool minusOffset = false; 167 bool isGMT = false; 168 size_t toGo = timeStrLen; 169 170 do { 171 if(*inCp == '.') { 172 if(foundDecimal) { 173 /* only legal once */ { 174 free(str); 175 return NULL_TIME; 176 } 177 } 178 foundDecimal++; 179 180 /* skip the decimal point... */ 181 inCp++; 182 toGo--; 183 if(toGo == 0) { 184 /* all done */ 185 break; 186 } 187 /* then all subsequent contiguous digits */ 188 while(isdigit(*inCp) && (toGo != 0)) { 189 inCp++; 190 toGo--; 191 } 192 } /* decimal point processing */ 193 else if((*inCp == '+') || (*inCp == '-')) { 194 /* Time zone offset - handle 2 or 4 chars */ 195 if((toGo != 2) & (toGo != 4)) { 196 free(str); 197 return NULL_TIME; 198 } 199 if(*inCp == '-') { 200 minusOffset = true; 201 } 202 inCp++; 203 hoursOffset = (10 * (inCp[0] - '0')) + (inCp[1] - '0'); 204 toGo -= 2; 205 if(toGo) { 206 minutesOffset = (10 * (inCp[0] - '0')) + (inCp[1] - '0'); 207 toGo -= 2; 208 } 209 } 210 else { 211 *outCp++ = *inCp++; 212 strLen++; 213 toGo--; 214 } 215 } while(toGo != 0); 216 217 if(str[strLen - 1] == 'Z') { 218 isGMT = true; 219 strLen--; 220 } 221 222 CFAbsoluteTime absTime; 223 absTime = parseGenTime(str, strLen); 224 free(str); 225 if(absTime == NULL_TIME) { 226 return NULL_TIME; 227 } 228 229 /* post processing needed? */ 230 if(isGMT) { 231 /* Nope, string was in GMT */ 232 return absTime; 233 } 234 if((minutesOffset != 0) || (hoursOffset != 0)) { 235 /* string contained explicit offset from GMT */ 236 if(minusOffset) { 237 absTime -= (minutesOffset * 60); 238 absTime -= (hoursOffset * 3600); 239 } 240 else { 241 absTime += (minutesOffset * 60); 242 absTime += (hoursOffset * 3600); 243 } 244 } 245 else { 246 /* implciit offset = local */ 247 CFTimeInterval tzDelta; 248 CFTimeZoneRef localZone = CFTimeZoneCopySystem(); 249 tzDelta = CFTimeZoneGetSecondsFromGMT (localZone, CFAbsoluteTimeGetCurrent()); 250 CFRelease(localZone); 251 absTime += tzDelta; 252 } 253 return absTime; 254} 255 256/* 257 * Convert CFAbsoluteTime to generalized time string, GMT format (4 digit year, 258 * trailing 'Z'). Caller allocated the output which is GENERAL_TIME_STRLEN+1 bytes. 259 */ 260void cfAbsTimeToGgenTime( 261 CFAbsoluteTime absTime, 262 char *genTime) 263{ 264 /* time zone = GMT */ 265 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); 266 CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(absTime, tz); 267 int seconds = (int)greg.second; 268 sprintf(genTime, "%04d%02d%02d%02d%02d%02dZ", 269 (int)greg.year, greg.month, greg.day, greg.hour, 270 greg.minute, seconds); 271} 272 273void ocspdSha1( 274 const void *data, 275 CC_LONG len, 276 unsigned char *md) // allocd by caller, CC_SHA1_DIGEST_LENGTH bytes 277{ 278 CC_SHA1_CTX ctx; 279 CC_SHA1_Init(&ctx); 280 CC_SHA1_Update(&ctx, data, len); 281 CC_SHA1_Final(md, &ctx); 282} 283 284void ocspdMD5( 285 const void *data, 286 CC_LONG len, 287 unsigned char *md) // allocd by caller, CC_MD5_DIGEST_LENGTH bytes 288{ 289 CC_MD5_CTX ctx; 290 CC_MD5_Init(&ctx); 291 CC_MD5_Update(&ctx, data, len); 292 CC_MD5_Final(md, &ctx); 293} 294 295void ocspdMD4( 296 const void *data, 297 CC_LONG len, 298 unsigned char *md) // allocd by caller, CC_MD4_DIGEST_LENGTH bytes 299{ 300 CC_MD4_CTX ctx; 301 CC_MD4_Init(&ctx); 302 CC_MD4_Update(&ctx, data, len); 303 CC_MD4_Final(md, &ctx); 304} 305 306void ocspdSHA256( 307 const void *data, 308 CC_LONG len, 309 unsigned char *md) // allocd by caller, CC_SHA256_DIGEST_LENGTH bytes 310{ 311 CC_SHA256_CTX ctx; 312 CC_SHA256_Init(&ctx); 313 CC_SHA256_Update(&ctx, data, len); 314 CC_SHA256_Final(md, &ctx); 315} 316 317/* 318 * How many items in a NULL-terminated array of pointers? 319 */ 320unsigned ocspdArraySize( 321 const void **array) 322{ 323 unsigned count = 0; 324 if (array) { 325 while (*array++) { 326 count++; 327 } 328 } 329 return count; 330} 331