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