1 /****************************************************************************
2 * *
3 * Get Certificate String Components *
4 * Copyright Peter Gutmann 1997-2009 *
5 * *
6 ****************************************************************************/
7
8 #include <stdio.h> /* For sprintf() */
9 #if defined( INC_ALL )
10 #include "cert.h"
11 #include "asn1_ext.h"
12 #else
13 #include "cert/cert.h"
14 #include "enc_dec/asn1_ext.h"
15 #endif /* Compiler-specific includes */
16
17 #ifdef USE_CERTIFICATES
18
19 /****************************************************************************
20 * *
21 * Utility Routines *
22 * *
23 ****************************************************************************/
24
25 /* The maximum magnitude of an individual OID arc. Anything larger than
26 this is most likely an error (or something from Microsoft) */
27
28 #define OID_ARC_MAX 0x1000000L /* 2 ^ 28 */
29
30 /* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */
31
32 #define MIN_ASCII_OIDSIZE 7
33
34 /* Convert a binary OID to its text form */
35
36 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
IN_BUFFER(binaryOidLen)37 static int oidToText( IN_BUFFER( binaryOidLen ) const BYTE *binaryOID,
38 IN_LENGTH_OID const int binaryOidLen,
39 OUT_BUFFER( maxOidLen, *oidLen ) char *oid,
40 IN_LENGTH_SHORT_MIN( 16 ) const int maxOidLen,
41 OUT_LENGTH_BOUNDED_Z( maxOidLen ) int *oidLen )
42 {
43 long value = 0;
44 int i, length = 0, subLen;
45
46 assert( isReadPtr( binaryOID, binaryOidLen ) );
47 assert( isWritePtr( oid, maxOidLen ) );
48 assert( isWritePtr( oidLen, sizeof( int ) ) );
49
50 REQUIRES( binaryOidLen >= MIN_OID_SIZE && \
51 binaryOidLen <= MAX_OID_SIZE && \
52 binaryOidLen == sizeofOID( binaryOID ) );
53 REQUIRES( maxOidLen >= 16 && maxOidLen < MAX_INTLENGTH_SHORT );
54
55 /* Clear return values */
56 memset( oid, 0, min( 16, maxOidLen ) );
57 *oidLen = 0;
58
59 for( i = 2; i < binaryOidLen; i++ )
60 {
61 const BYTE data = binaryOID[ i ];
62 const long valTmp = value << 7;
63
64 /* Pick apart the encoding */
65 if( value == 0 && data == 0x80 )
66 {
67 /* Invalid leading zero value, ( 0x80 & 0x7F ) == 0 */
68 return( CRYPT_ERROR_BADDATA );
69 }
70 if( value >= ( OID_ARC_MAX >> 7 ) || \
71 valTmp >= OID_ARC_MAX - ( data & 0x7F ) )
72 return( CRYPT_ERROR_BADDATA ); /* Overflow */
73 value = valTmp | ( data & 0x7F );
74 if( value < 0 || value > OID_ARC_MAX )
75 return( CRYPT_ERROR_BADDATA ); /* Range error */
76 if( !( data & 0x80 ) )
77 {
78 /* Make sure that we don't overflow the buffer. The value 20 is
79 the maximum magnitude of a 64-bit int plus space plus 1-byte
80 overflow */
81 if( length >= maxOidLen - 20 )
82 return( CRYPT_ERROR_BADDATA );
83
84 if( length == 0 )
85 {
86 long x, y;
87
88 /* The first two levels are encoded into one byte since the
89 root level has only 3 nodes (40*x + y), however if x =
90 joint-iso-itu-t(2) then y may be > 39, so we have to add
91 special-case handling for this */
92 x = value / 40;
93 y = value % 40;
94 if( x > 2 )
95 {
96 /* Handle special case for large y if x == 2 */
97 y += ( x - 2 ) * 40;
98 x = 2;
99 }
100 if( x < 0 || x > 2 || y < 0 || \
101 ( ( x < 2 && y > 39 ) || \
102 ( x == 2 && ( y > 50 && y != 100 ) ) ) )
103 {
104 /* If x = 0 or 1 then y has to be 0...39, for x = 3
105 it can take any value but there are no known
106 assigned values over 50 except for one contrived
107 example in X.690 which sets y = 100, so if we see
108 something outside this range it's most likely an
109 encoding error rather than some bizarre new ID
110 that's just appeared */
111 return( CRYPT_ERROR_BADDATA );
112 }
113 subLen = sprintf_s( oid, maxOidLen, "%ld %ld", x, y );
114 }
115 else
116 {
117 subLen = sprintf_s( oid + length, maxOidLen - length,
118 " %ld", value );
119 }
120 if( subLen < 2 || subLen > maxOidLen - length )
121 return( CRYPT_ERROR_BADDATA );
122 length += subLen;
123 value = 0;
124 }
125
126 }
127 if( value != 0 )
128 {
129 /* We stopped in the middle of a continued value, it's an invalid
130 encoding */
131 return( CRYPT_ERROR_BADDATA );
132 }
133 *oidLen = length;
134
135 return( CRYPT_OK );
136 }
137
138 /* Convert an ASCII OID arc sequence into an encoded OID. We allow dots as
139 well as whitespace for arc separators, these are an IETF-ism but are in
140 common use */
141
142 CHECK_RETVAL_RANGE( 0, CRYPT_MAX_TEXTSIZE ) STDC_NONNULL_ARG( ( 1, 3 ) ) \
scanValue(IN_BUFFER (strMaxLength)const char * string,IN_LENGTH_TEXT const int strMaxLength,OUT_INT_Z long * value)143 static int scanValue( IN_BUFFER( strMaxLength ) const char *string,
144 IN_LENGTH_TEXT const int strMaxLength,
145 OUT_INT_Z long *value )
146 {
147 int intValue, index, status;
148
149 assert( isReadPtr( string, strMaxLength ) );
150 assert( isWritePtr( value, sizeof( long ) ) );
151
152 REQUIRES( strMaxLength > 0 && strMaxLength <= CRYPT_MAX_TEXTSIZE );
153
154 /* Clear return value */
155 *value = 0;
156
157 /* Look for the end of the arc */
158 for( index = 0; index < strMaxLength; index++ )
159 {
160 if( string[ index ] == ' ' || string[ index ] == '.' )
161 break;
162 }
163 if( index <= 0 || index > CRYPT_MAX_TEXTSIZE )
164 return( -1 );
165 status = strGetNumeric( string, index, &intValue, 0, OID_ARC_MAX );
166 if( cryptStatusError( status ) )
167 return( -1 );
168 *value = intValue;
169 if( index < strMaxLength && \
170 ( string[ index ] == ' ' || string[ index ] == '.' ) )
171 {
172 /* There's more to go, skip the delimiter */
173 index++;
174 }
175 return( index );
176 }
177
178 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
textToOID(IN_BUFFER (textOidLength)const char * textOID,IN_LENGTH_TEXT const int textOidLength,OUT_BUFFER (binaryOidMaxLen,* binaryOidLen)BYTE * binaryOID,IN_LENGTH_SHORT const int binaryOidMaxLen,OUT_LENGTH_BOUNDED_Z (binaryOidMaxLen)int * binaryOidLen)179 int textToOID( IN_BUFFER( textOidLength ) const char *textOID,
180 IN_LENGTH_TEXT const int textOidLength,
181 OUT_BUFFER( binaryOidMaxLen, *binaryOidLen ) BYTE *binaryOID,
182 IN_LENGTH_SHORT const int binaryOidMaxLen,
183 OUT_LENGTH_BOUNDED_Z( binaryOidMaxLen ) int *binaryOidLen )
184 {
185 const char *textOidPtr;
186 long value, value2;
187 int length = 3, subLen, dataLeft, iterationCount, status;
188
189 assert( isReadPtr( textOID, textOidLength ) );
190 assert( isWritePtr( binaryOID, binaryOidMaxLen ) );
191 assert( isWritePtr( binaryOidLen, sizeof( int ) ) );
192
193 REQUIRES( textOidLength >= MIN_ASCII_OIDSIZE && \
194 textOidLength <= CRYPT_MAX_TEXTSIZE );
195 REQUIRES( binaryOidMaxLen >= 5 && \
196 binaryOidMaxLen < MAX_INTLENGTH_SHORT );
197
198 /* Clear return value */
199 memset( binaryOID, 0, min( 16, binaryOidMaxLen ) );
200 *binaryOidLen = 0;
201
202 /* Perform some basic checks on the OID data */
203 status = dataLeft = strStripWhitespace( &textOidPtr, textOID,
204 textOidLength );
205 if( cryptStatusError( status ) )
206 return( CRYPT_ERROR_BADDATA );
207
208 /* Make sure that the first two arcs are in order */
209 subLen = scanValue( textOidPtr, dataLeft, &value );
210 if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
211 return( CRYPT_ERROR_BADDATA );
212 textOidPtr += subLen;
213 dataLeft -= subLen;
214 if( dataLeft <= 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
215 return( CRYPT_ERROR_BADDATA );
216 subLen = scanValue( textOidPtr, dataLeft, &value2 );
217 if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
218 return( CRYPT_ERROR_BADDATA );
219 textOidPtr += subLen;
220 dataLeft -= subLen;
221 if( dataLeft <= 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
222 return( CRYPT_ERROR_BADDATA );
223 if( value < 0 || value > 2 || value2 < 1 || \
224 ( ( value < 2 && value2 > 39 ) || ( value == 2 && value2 > 175 ) ) )
225 return( CRYPT_ERROR_BADDATA );
226 binaryOID[ 0 ] = 0x06; /* OBJECT IDENTIFIER tag */
227 binaryOID[ 2 ] = ( BYTE )( ( value * 40 ) + value2 );
228
229 /* Convert the remaining arcs */
230 for( iterationCount = 0;
231 dataLeft > 0 && iterationCount < FAILSAFE_ITERATIONS_MED;
232 iterationCount++ )
233 {
234 BOOLEAN hasHighBits = FALSE;
235
236 /* Scan the next value and write the high octets (if necessary) with
237 flag bits set, followed by the final octet */
238 subLen = scanValue( textOidPtr, dataLeft, &value );
239 if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
240 return( CRYPT_ERROR_BADDATA );
241 textOidPtr += subLen;
242 dataLeft -= subLen;
243 if( dataLeft < 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
244 return( CRYPT_ERROR_BADDATA );
245 if( value >= 0x200000L ) /* 2^21 */
246 {
247 if( length >= binaryOidMaxLen )
248 return( CRYPT_ERROR_BADDATA );
249 binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 21 ) );
250 value %= 0x200000L;
251 hasHighBits = TRUE;
252 }
253 if( ( value >= 0x4000 ) || hasHighBits ) /* 2^14 */
254 {
255 if( length >= binaryOidMaxLen )
256 return( CRYPT_ERROR_BADDATA );
257 binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 14 ) );
258 value %= 0x4000;
259 hasHighBits = TRUE;
260 }
261 if( ( value >= 0x80 ) || hasHighBits ) /* 2^7 */
262 {
263 if( length >= binaryOidMaxLen )
264 return( CRYPT_ERROR_BADDATA );
265 binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 7 ) );
266 value %= 128;
267 }
268 if( length >= binaryOidMaxLen )
269 return( CRYPT_ERROR_BADDATA );
270 binaryOID[ length++ ] = intToByte( value );
271 }
272 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
273 binaryOID[ 1 ] = intToByte( length - 2 );
274 *binaryOidLen = length;
275
276 return( CRYPT_OK );
277 }
278
279 /****************************************************************************
280 * *
281 * Get Certificate Components *
282 * *
283 ****************************************************************************/
284
285 /* Get a certificate component */
286
287 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
getCertAttributeComponent(const CERT_INFO * certInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)288 static int getCertAttributeComponent( const CERT_INFO *certInfoPtr,
289 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
290 OUT_BUFFER_OPT( certInfoMaxLength, *certInfoLength ) \
291 void *certInfo,
292 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
293 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
294 int *certInfoLength )
295 {
296 ATTRIBUTE_PTR *attributePtr;
297 void *dataPtr;
298 int dataLength, status;
299
300 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
301 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
302 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
303 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
304
305 REQUIRES( certInfoType > CRYPT_ATTRIBUTE_NONE && \
306 certInfoType < CRYPT_ATTRIBUTE_LAST );
307 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
308 ( certInfo != NULL && \
309 certInfoMaxLength > 0 && \
310 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
311
312 /* Clear return values */
313 if( certInfo != NULL )
314 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
315 *certInfoLength = 0;
316
317 /* Try and find this attribute in the attribute list */
318 attributePtr = findAttributeComponent( certInfoPtr, certInfoType );
319 if( attributePtr == NULL )
320 return( CRYPT_ERROR_NOTFOUND );
321
322 /* String fields never have default values (only BOOLEANs do) and never
323 denote complete-attribute entries (these are indicated by a present/
324 not-present BOOLEAN) */
325 ENSURES( !checkAttributeProperty( attributePtr,
326 ATTRIBUTE_PROPERTY_DEFAULTVALUE ) );
327 ENSURES( !checkAttributeProperty( attributePtr,
328 ATTRIBUTE_PROPERTY_COMPLETEATRIBUTE ) );
329
330 /* If the data type is an OID we have to convert it to a human-readable
331 form before we return it */
332 if( checkAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_OID ) )
333 {
334 char textOID[ ( CRYPT_MAX_TEXTSIZE * 2 ) + 8 ];
335 int textOidLength;
336
337 status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
338 if( cryptStatusError( status ) )
339 return( status );
340 status = oidToText( dataPtr, dataLength, textOID,
341 CRYPT_MAX_TEXTSIZE * 2, &textOidLength );
342 if( cryptStatusError( status ) )
343 return( status );
344 *certInfoLength = textOidLength;
345 if( certInfo == NULL )
346 return( CRYPT_OK );
347 return( attributeCopyParams( certInfo, certInfoMaxLength,
348 certInfoLength, textOID,
349 textOidLength ) );
350 }
351
352 /* Get the attribute component data */
353 status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
354 if( cryptStatusError( status ) )
355 return( status );
356 return( attributeCopyParams( certInfo, certInfoMaxLength,
357 certInfoLength, dataPtr, dataLength ) );
358 }
359
360 /* Get the hash of a certificate */
361
362 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
getCertHash(INOUT CERT_INFO * certInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)363 static int getCertHash( INOUT CERT_INFO *certInfoPtr,
364 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
365 OUT_BUFFER_OPT( certInfoMaxLength, \
366 *certInfoLength ) void *certInfo,
367 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
368 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
369 int *certInfoLength )
370 {
371 static const MAP_TABLE hashAlgoMapTbl[] = {
372 { CRYPT_CERTINFO_FINGERPRINT_SHA1, CRYPT_ALGO_SHA1 },
373 { CRYPT_CERTINFO_FINGERPRINT_SHA2, CRYPT_ALGO_SHA2 },
374 { CRYPT_CERTINFO_FINGERPRINT_SHAng, CRYPT_ALGO_SHAng },
375 { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
376 };
377 HASH_FUNCTION_ATOMIC hashFunctionAtomic;
378 BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
379 int hashAlgo, hashSize, status;
380
381 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
382 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
383 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
384 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
385
386 REQUIRES( certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHA1 || \
387 certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHA2 || \
388 certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHAng );
389 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
390 ( certInfo != NULL && \
391 certInfoMaxLength > 0 && \
392 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
393
394 /* Clear return values */
395 if( certInfo != NULL )
396 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
397 *certInfoLength = 0;
398
399 /* Get the hash algorithm information */
400 status = mapValue( certInfoType, &hashAlgo, hashAlgoMapTbl,
401 FAILSAFE_ARRAYSIZE( hashAlgoMapTbl, MAP_TABLE ) );
402 ENSURES( cryptStatusOK( status ) );
403 getHashAtomicParameters( hashAlgo, 0, &hashFunctionAtomic, &hashSize );
404 *certInfoLength = hashSize;
405 if( certInfo == NULL )
406 return( CRYPT_OK );
407 ENSURES( certInfoPtr->certificate != NULL );
408
409 /* Write the hash (fingerprint) to the output */
410 if( hashAlgo == CRYPT_ALGO_SHA1 && certInfoPtr->certHashSet )
411 {
412 /* If we've got a cached certificate hash present, return that instead of
413 re-hashing the certificate */
414 return( attributeCopyParams( certInfo, certInfoMaxLength,
415 certInfoLength, certInfoPtr->certHash,
416 KEYID_SIZE ) );
417 }
418 hashFunctionAtomic( hash, CRYPT_MAX_HASHSIZE, certInfoPtr->certificate,
419 certInfoPtr->certificateSize );
420 if( hashAlgo == CRYPT_ALGO_SHA1 )
421 {
422 /* Remember the hash/fingerprint/oobCertID/certHash/thumbprint/
423 whatever for later since this is reused frequently */
424 memcpy( certInfoPtr->certHash, hash, hashSize );
425 certInfoPtr->certHashSet = TRUE;
426 }
427 return( attributeCopyParams( certInfo, certInfoMaxLength,
428 certInfoLength, hash, hashSize ) );
429 }
430
431 /* Get the ESSCertID for a certificate */
432
433 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
getESSCertID(INOUT CERT_INFO * certInfoPtr,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)434 static int getESSCertID( INOUT CERT_INFO *certInfoPtr,
435 OUT_BUFFER_OPT( certInfoMaxLength, \
436 *certInfoLength ) void *certInfo,
437 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
438 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
439 int *certInfoLength )
440 {
441 STREAM stream;
442 BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
443 int certHashSize, issuerSerialDataSize, status;
444
445 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
446 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
447 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
448 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
449
450 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
451 ( certInfo != NULL && \
452 certInfoMaxLength > 0 && \
453 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
454
455 /* Clear return values */
456 if( certInfo != NULL )
457 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
458 *certInfoLength = 0;
459
460 /* Get the certificate ID */
461 status = getCertHash( certInfoPtr, CRYPT_CERTINFO_FINGERPRINT_SHA1,
462 certHash, CRYPT_MAX_HASHSIZE, &certHashSize );
463 if( cryptStatusError( status ) )
464 return( status );
465 REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );
466
467 /* Write the ESSCertID:
468
469 ESSCertID ::= SEQUENCE {
470 certHash OCTET STRING SIZE(20),
471 issuerSerial SEQUENCE {
472 issuer SEQUENCE { [4] EXPLICIT Name },
473 serial INTEGER
474 }
475 } */
476 issuerSerialDataSize = ( int ) \
477 sizeofObject( sizeofObject( certInfoPtr->issuerDNsize ) ) + \
478 sizeofInteger( certInfoPtr->cCertCert->serialNumber,
479 certInfoPtr->cCertCert->serialNumberLength );
480 *certInfoLength = ( int ) \
481 sizeofObject( sizeofObject( certHashSize ) + \
482 sizeofObject( issuerSerialDataSize ) );
483 if( certInfo == NULL )
484 return( CRYPT_OK );
485 if( *certInfoLength <= 0 || *certInfoLength > certInfoMaxLength )
486 return( CRYPT_ERROR_OVERFLOW );
487 sMemOpen( &stream, certInfo, *certInfoLength );
488 writeSequence( &stream, sizeofObject( certHashSize ) + \
489 sizeofObject( issuerSerialDataSize ) );
490 writeOctetString( &stream, certHash, certHashSize, DEFAULT_TAG );
491 writeSequence( &stream, issuerSerialDataSize );
492 writeSequence( &stream, sizeofObject( certInfoPtr->issuerDNsize ) );
493 writeConstructed( &stream, certInfoPtr->issuerDNsize, 4 );
494 swrite( &stream, certInfoPtr->issuerDNptr, certInfoPtr->issuerDNsize );
495 status = writeInteger( &stream, certInfoPtr->cCertCert->serialNumber,
496 certInfoPtr->cCertCert->serialNumberLength,
497 DEFAULT_TAG );
498 sMemDisconnect( &stream );
499 ENSURES( cryptStatusOK( status ) );
500
501 return( status );
502 }
503
504 /****************************************************************************
505 * *
506 * Get Validity Components *
507 * *
508 ****************************************************************************/
509
510 #ifdef USE_CERTVAL
511
512 /* Get a pointer to the currently selected validity time */
513
514 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
getValidityTimePtr(const CERT_INFO * certInfoPtr)515 time_t *getValidityTimePtr( const CERT_INFO *certInfoPtr )
516 {
517 CERT_VAL_INFO *certValInfo = certInfoPtr->cCertVal;
518
519 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
520
521 REQUIRES_N( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE );
522
523 /* If there's a specific validity entry selected get its invalidity time,
524 otherwise if there are invalid certificates present get the first
525 certificate's invalidity time, otherwise get the default invalidity
526 time */
527 return( ( certValInfo->currentValidity != NULL ) ? \
528 &certValInfo->currentValidity->invalidityTime : \
529 ( certValInfo->validityInfo != NULL ) ? \
530 &certValInfo->validityInfo->invalidityTime : NULL );
531 }
532 #endif /* USE_CERTVAL */
533
534 /****************************************************************************
535 * *
536 * Get Revocation Components *
537 * *
538 ****************************************************************************/
539
540 #ifdef USE_CERTREV
541
542 /* Encode a single CRL entry into the external format, used when storing a
543 CRL to a certificate store */
544
545 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
getCrlEntry(INOUT CERT_INFO * certInfoPtr,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)546 static int getCrlEntry( INOUT CERT_INFO *certInfoPtr,
547 OUT_BUFFER_OPT( certInfoMaxLength, \
548 *certInfoLength ) void *certInfo,
549 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
550 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
551 int *certInfoLength )
552 {
553 CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
554 STREAM stream;
555 WRITECERT_FUNCTION writeCertFunction;
556 int crlEntrySize DUMMY_INIT, status;
557
558 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
559 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
560 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
561 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
562
563 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
564 ( certInfo != NULL && \
565 certInfoMaxLength > 0 && \
566 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
567 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL );
568
569 /* Clear return values */
570 if( certInfo != NULL )
571 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
572 *certInfoLength = 0;
573
574 if( certRevInfo->currentRevocation == NULL )
575 return( CRYPT_ERROR_NOTFOUND );
576
577 /* Determine how big the encoded CRL entry will be. Doing it directly
578 in this manner is somewhat ugly but the only other way to do it would
579 be to pseudo-sign the certificate object in order to write the data,
580 which doesn't work for CRL entries where we could end up pseudo-
581 signing it multiple times */
582 writeCertFunction = getCertWriteFunction( CRYPT_CERTTYPE_CRL );
583 ENSURES( writeCertFunction != NULL );
584 sMemNullOpen( &stream );
585 status = writeCertFunction( &stream, certInfoPtr, NULL, CRYPT_UNUSED );
586 if( cryptStatusOK( status ) )
587 crlEntrySize = stell( &stream );
588 sMemClose( &stream );
589 if( cryptStatusError( status ) )
590 return( status );
591
592 /* Write the encoded single CRL entry */
593 *certInfoLength = crlEntrySize;
594 if( certInfo == NULL )
595 return( CRYPT_OK );
596 if( crlEntrySize <= 0 || crlEntrySize > certInfoMaxLength )
597 return( CRYPT_ERROR_OVERFLOW );
598 sMemOpen( &stream, certInfo, crlEntrySize );
599 status = writeCertFunction( &stream, certInfoPtr, NULL, CRYPT_UNUSED );
600 sMemDisconnect( &stream );
601
602 return( status );
603 }
604
605 /* Get a pointer to the currently selected revocation time */
606
607 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
getRevocationTimePtr(const CERT_INFO * certInfoPtr)608 time_t *getRevocationTimePtr( const CERT_INFO *certInfoPtr )
609 {
610 CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
611
612 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
613
614 REQUIRES_N( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
615 certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
616 certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
617
618 /* If there's a specific revocation entry selected, get its revocation
619 time, otherwise if there are revoked certificates present get the
620 first certificate's revocation time, otherwise get the default
621 revocation time */
622 return( ( certRevInfo->currentRevocation != NULL ) ? \
623 &certRevInfo->currentRevocation->revocationTime : \
624 ( certRevInfo->revocations != NULL ) ? \
625 &certRevInfo->revocations->revocationTime : \
626 ( certRevInfo->revocationTime ) ? \
627 &certRevInfo->revocationTime : NULL );
628 }
629 #endif /* USE_CERTREV */
630
631 /****************************************************************************
632 * *
633 * Get Certificate Owner Components *
634 * *
635 ****************************************************************************/
636
637 /* Get the issuerAndSerialNumber for a certificate */
638
639 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
getIAndS(const CERT_INFO * certInfoPtr,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)640 static int getIAndS( const CERT_INFO *certInfoPtr,
641 OUT_BUFFER_OPT( certInfoMaxLength, \
642 *certInfoLength ) void *certInfo,
643 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
644 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
645 int *certInfoLength )
646 {
647 STREAM stream;
648 void *serialNumber;
649 int serialNumberLength, status;
650
651 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
652 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
653 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
654 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
655
656 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
657 ( certInfo != NULL && \
658 certInfoMaxLength > 0 && \
659 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
660
661 /* Clear return values */
662 if( certInfo != NULL )
663 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
664 *certInfoLength = 0;
665
666 #ifdef USE_CERTREV
667 /* If it's a CRL, use the serial number of the currently selected CRL
668 entry */
669 if( certInfoPtr->type == CRYPT_CERTTYPE_CRL )
670 {
671 REVOCATION_INFO *crlInfoPtr = certInfoPtr->cCertRev->currentRevocation;
672
673 REQUIRES( crlInfoPtr != NULL );
674
675 serialNumber = crlInfoPtr->id;
676 serialNumberLength = crlInfoPtr->idLength;
677 }
678 else
679 #endif /* USE_CERTREV */
680 {
681 serialNumber = certInfoPtr->cCertCert->serialNumber;
682 serialNumberLength = certInfoPtr->cCertCert->serialNumberLength;
683 }
684 ENSURES( serialNumber != NULL );
685 *certInfoLength = ( int ) \
686 sizeofObject( certInfoPtr->issuerDNsize + \
687 sizeofInteger( serialNumber, \
688 serialNumberLength ) );
689 if( certInfo == NULL )
690 return( CRYPT_OK );
691 if( *certInfoLength <= 0 || *certInfoLength > certInfoMaxLength )
692 return( CRYPT_ERROR_OVERFLOW );
693 sMemOpen( &stream, certInfo, *certInfoLength );
694 writeSequence( &stream, certInfoPtr->issuerDNsize + \
695 sizeofInteger( serialNumber, serialNumberLength ) );
696 swrite( &stream, certInfoPtr->issuerDNptr, certInfoPtr->issuerDNsize );
697 status = writeInteger( &stream, serialNumber, serialNumberLength,
698 DEFAULT_TAG );
699 sMemDisconnect( &stream );
700
701 return( status );
702 }
703
704 /* Look for a named DN component (e.g. "surname = Smith") in an RFC 1779-
705 encoded DN. We have to use the text-string encoded form because we're
706 looking for arbitrarily odd components not all of which are handled
707 directly by cryptlib */
708
709 #if 0 /* 18/7/08 Unlikely that we'd ever find a certificate this broken,
710 and it's just a potential attack vector due to the complexity of
711 the processing */
712
713 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 6 ) ) \
714 static int extractDnComponent( IN_BUFFER( encodedDnLength ) \
715 const char *encodedDn,
716 IN_LENGTH_SHORT const int encodedDnLength,
717 IN_BUFFER( componentNameLength ) \
718 const char *componentName,
719 IN_LENGTH_SHORT const int componentNameLength,
720 OUT_LENGTH_SHORT_Z int *startOffset,
721 OUT_LENGTH_SHORT_Z int *length )
722 {
723 int startPos, endPos;
724
725 assert( isReadPtr( encodedDn, encodedDnLength ) );
726 assert( isReadPtr( componentName, componentNameLength ) );
727 assert( isWritePtr( startOffset, sizeof( int ) ) );
728 assert( isWritePtr( length, sizeof( int ) ) );
729
730 REQUIRES( encodedDnLength > 0 && \
731 encodedDnLength < MAX_INTLENGTH_SHORT );
732 REQUIRES( componentNameLength > 0 && \
733 componentNameLength < MAX_INTLENGTH_SHORT );
734
735 /* Clear return values */
736 *startOffset = *length = 0;
737
738 /* Try and find the component type name in the RFC 1779-encoded DN
739 string. This scans the DN string for a matching type in a
740 type-and-value pair, e.g. "surname = Smith" */
741 startPos = strFindStr( encodedDn, encodedDnLength,
742 componentName, componentNameLength );
743 if( startPos < 0 )
744 return( -1 );
745 startPos += componentNameLength; /* Skip type indicator */
746
747 /* Extract the component value */
748 for( endPos = startPos; endPos < encodedDnLength && \
749 encodedDn[ endPos ] != ',' && \
750 encodedDn[ endPos ] != '+'; endPos++ );
751 if( endPos > startPos && \
752 encodedDn[ endPos ] == '+' && \
753 encodedDn[ endPos - 1 ] == ' ' )
754 endPos--; /* Strip trailing space */
755 if( endPos <= startPos )
756 return( -1 );
757
758 *startOffset = startPos;
759 *length = endPos - startPos;
760
761 return( CRYPT_OK );
762 }
763
764 /* Assemble name components from an RFC 1779-encoded DN string. We have to
765 use the text-string encoded form because we're looking for arbitrarily
766 odd components not all of which are handled directly by cryptlib */
767
768 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 4 ) ) \
769 static int getNameFromDN( OUT_BUFFER_OPT( nameMaxLength, *nameLength ) \
770 void *name,
771 IN_LENGTH_SHORT_Z const int nameMaxLength,
772 OUT_LENGTH_BOUNDED_Z( nameMaxLength ) \
773 int *nameLength,
774 IN_BUFFER( encodedDnLength ) const char *encodedDn,
775 IN_LENGTH_SHORT const int encodedDnLength )
776 {
777 int startPos, length, status;
778
779 assert( ( name == NULL && nameMaxLength == 0 ) || \
780 ( isWritePtr( name, nameMaxLength ) ) );
781 assert( isWritePtr( nameLength, sizeof( int ) ) );
782 assert( isReadPtr( encodedDn, encodedDnLength ) );
783
784 REQUIRES( ( name == NULL && nameMaxLength == 0 ) || \
785 ( name != NULL && \
786 nameMaxLength > 0 && \
787 nameMaxLength < MAX_INTLENGTH_SHORT ) );
788 REQUIRES( encodedDnLength > 0 && \
789 encodedDnLength < MAX_INTLENGTH_SHORT );
790
791 /* Clear return values */
792 if( name != NULL )
793 memset( name, 0, min( 16, nameMaxLength ) );
794 *nameLength = 0;
795
796 /* Look for a pseudonym */
797 status = extractDnComponent( encodedDn, encodedDnLength,
798 "oid.2.5.4.65=", 13, &startPos, &length );
799 if( cryptStatusOK( status ) && \
800 length > 0 && length <= nameMaxLength )
801 {
802 return( attributeCopyParams( name, nameMaxLength, nameLength,
803 encodedDn + startPos, length ) );
804 }
805
806 /* Look for givenName + surname */
807 status = extractDnComponent( encodedDn, encodedDnLength,
808 "G=", 2, &startPos, &length );
809 if( cryptStatusOK( status ) && \
810 length > 0 && length <= nameMaxLength )
811 {
812 char nameBuffer[ MAX_ATTRIBUTE_SIZE + 8 ];
813 int startPos2, length2;
814
815 status = extractDnComponent( encodedDn, encodedDnLength,
816 "S=", 2, &startPos2, &length2 );
817 if( cryptStatusOK( status ) && \
818 length2 > 0 && length + length2 <= nameMaxLength && \
819 length + length2 < MAX_ATTRIBUTE_SIZE )
820 {
821 memcpy( nameBuffer, encodedDn + startPos, length );
822 memcpy( nameBuffer + length, encodedDn + startPos2, length2 );
823 return( attributeCopyParams( name, nameMaxLength, nameLength,
824 nameBuffer, length + length2 ) );
825 }
826 }
827
828 /* We couldn't find anything useful */
829 return( CRYPT_ERROR_NOTFOUND );
830 }
831 #endif /* 0 */
832
833 /* Get the certificate holder's name, usually the commonName but if that's
834 not present then some commonName-equivalent */
835
836 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
getHolderName(const CERT_INFO * certInfoPtr,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)837 static int getHolderName( const CERT_INFO *certInfoPtr,
838 OUT_BUFFER_OPT( certInfoMaxLength, \
839 *certInfoLength ) void *certInfo,
840 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
841 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
842 int *certInfoLength )
843 {
844 int status;
845
846 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
847 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
848 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
849 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
850
851 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
852 ( certInfo != NULL && \
853 certInfoMaxLength > 0 && \
854 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
855
856 /* Clear return values */
857 if( certInfo != NULL )
858 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
859 *certInfoLength = 0;
860
861 /* First we try for a CN */
862 status = getDNComponentValue( certInfoPtr->subjectName,
863 CRYPT_CERTINFO_COMMONNAME, 0, certInfo,
864 certInfoMaxLength, certInfoLength );
865 if( cryptStatusOK( status ) )
866 return( CRYPT_OK );
867
868 #if 0 /* 18/7/08 Unlikely that we'd ever find a certificate this broken,
869 and it's just a potential attack vector due to the complexity of
870 the processing */
871 /* If that fails we try for either a pseudonym or givenName + surname.
872 Since these are part of the vast collection of oddball DN attributes
873 that aren't handled directly we have to get the encoded DN form and
874 look for them by OID (ugh) */
875 sMemOpen( &stream, encodedDnBuffer, MAX_ATTRIBUTE_SIZE );
876 status = writeDNstring( &stream, certInfoPtr->subjectName );
877 if( cryptStatusOK( status ) )
878 status = getNameFromDN( certInfo, certInfoMaxLength, certInfoLength,
879 encodedDnBuffer, stell( &stream ) );
880 sMemDisconnect( &stream );
881 if( cryptStatusOK( status ) )
882 return( status );
883 #endif /* 0 */
884
885 /* It's possible (although highly unlikely) that a certificate won't
886 have a usable CN-equivalent in some form, in which case we use the OU
887 instead. If that also fails we use the O. This gets a bit messy,
888 but duplicating the OU / O into the CN seems to be the best way to
889 handle this */
890 status = getDNComponentValue( certInfoPtr->subjectName,
891 CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, 0,
892 certInfo, certInfoMaxLength,
893 certInfoLength );
894 if( cryptStatusError( status ) )
895 status = getDNComponentValue( certInfoPtr->subjectName,
896 CRYPT_CERTINFO_ORGANIZATIONNAME, 0,
897 certInfo, certInfoMaxLength,
898 certInfoLength );
899 return( status );
900 }
901
902 /* Get the certificate holder's URI, usually an email address but sometimes
903 also a URL */
904
905 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
getHolderURI(const CERT_INFO * certInfoPtr,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)906 static int getHolderURI( const CERT_INFO *certInfoPtr,
907 OUT_BUFFER_OPT( certInfoMaxLength, \
908 *certInfoLength ) void *certInfo,
909 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
910 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
911 int *certInfoLength )
912 {
913 ATTRIBUTE_PTR *attributePtr;
914 void *dataPtr;
915 int dataLength, status;
916
917 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
918 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
919 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
920 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
921
922 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
923 ( certInfo != NULL && \
924 certInfoMaxLength > 0 && \
925 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
926
927 /* Clear return values */
928 if( certInfo != NULL )
929 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
930 *certInfoLength = 0;
931
932 /* Find the subjectAltName, which contains the URI information */
933 attributePtr = findAttribute( certInfoPtr->attributes,
934 CRYPT_CERTINFO_SUBJECTALTNAME, TRUE );
935 if( attributePtr == NULL )
936 return( CRYPT_ERROR_NOTFOUND );
937
938 /* There's altName data present, try for an email address and if that
939 fails, a URL and an FQDN */
940 attributePtr = findAttributeField( attributePtr,
941 CRYPT_CERTINFO_SUBJECTALTNAME,
942 CRYPT_CERTINFO_RFC822NAME );
943 if( attributePtr == NULL )
944 attributePtr = findAttributeField( attributePtr,
945 CRYPT_CERTINFO_SUBJECTALTNAME,
946 CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
947 if( attributePtr == NULL )
948 attributePtr = findAttributeField( attributePtr,
949 CRYPT_CERTINFO_SUBJECTALTNAME,
950 CRYPT_CERTINFO_DNSNAME );
951 if( attributePtr == NULL )
952 return( CRYPT_ERROR_NOTFOUND );
953
954 /* Get the attribute component data */
955 status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
956 if( cryptStatusError( status ) )
957 return( status );
958 return( attributeCopyParams( certInfo, certInfoMaxLength,
959 certInfoLength, dataPtr, dataLength ) );
960 }
961
962 /****************************************************************************
963 * *
964 * Get Miscellaneous Certificate Components *
965 * *
966 ****************************************************************************/
967
968 #ifdef USE_PKIUSER
969
970 /* Encode PKI user information (IDs and passwords) into the external
971 text-encoded format */
972
973 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
getPkiUserInfo(const CERT_INFO * certInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)974 static int getPkiUserInfo( const CERT_INFO *certInfoPtr,
975 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
976 OUT_BUFFER_OPT( certInfoMaxLength, \
977 *certInfoLength ) void *certInfo,
978 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
979 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
980 int *certInfoLength )
981 {
982 CERT_PKIUSER_INFO *certUserInfo = certInfoPtr->cCertUser;
983 char encUserInfo[ CRYPT_MAX_TEXTSIZE + 8 ];
984 BYTE userInfo[ 128 + 8 ], *userInfoPtr = userInfo;
985 int userInfoLength, encUserInfoLength, status;
986
987 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
988 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
989 ( isWritePtr( certInfo, certInfoMaxLength ) ) );
990 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
991
992 REQUIRES( certInfoType == CRYPT_CERTINFO_PKIUSER_ID || \
993 certInfoType == CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD || \
994 certInfoType == CRYPT_CERTINFO_PKIUSER_REVPASSWORD );
995 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
996 ( certInfo != NULL && \
997 certInfoMaxLength > 0 && \
998 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
999
1000 /* Clear return values */
1001 if( certInfo != NULL )
1002 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
1003 *certInfoLength = 0;
1004
1005 if( certInfoType == CRYPT_CERTINFO_PKIUSER_ID )
1006 {
1007 status = getCertAttributeComponent( certInfoPtr,
1008 CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
1009 userInfo, 128, &userInfoLength );
1010 ENSURES( cryptStatusOK( status ) );
1011 }
1012 else
1013 {
1014 userInfoPtr = ( certInfoType == CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD ) ? \
1015 certUserInfo->pkiIssuePW : certUserInfo->pkiRevPW;
1016 userInfoLength = PKIUSER_AUTHENTICATOR_SIZE;
1017 }
1018 status = encodePKIUserValue( encUserInfo, CRYPT_MAX_TEXTSIZE,
1019 &encUserInfoLength, userInfoPtr,
1020 userInfoLength,
1021 ( certInfoType == \
1022 CRYPT_CERTINFO_PKIUSER_ID ) ? 3 : 4 );
1023 zeroise( userInfo, CRYPT_MAX_TEXTSIZE );
1024 if( cryptStatusError( status ) )
1025 return( status );
1026 ENSURES( cryptStatusOK( \
1027 decodePKIUserValue( userInfo, 128, &userInfoLength,
1028 encUserInfo, encUserInfoLength ) ) );
1029 status = attributeCopyParams( certInfo, certInfoMaxLength,
1030 certInfoLength, encUserInfo,
1031 encUserInfoLength );
1032 zeroise( encUserInfo, CRYPT_MAX_TEXTSIZE );
1033
1034 return( status );
1035 }
1036 #endif /* USE_PKIUSER */
1037
1038 /****************************************************************************
1039 * *
1040 * Get a Certificate Component *
1041 * *
1042 ****************************************************************************/
1043
1044 /* Get a certificate component */
1045
1046 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
getCertComponentString(INOUT CERT_INFO * certInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,OUT_BUFFER_OPT (certInfoMaxLength,* certInfoLength)void * certInfo,IN_LENGTH_SHORT_Z const int certInfoMaxLength,OUT_LENGTH_BOUNDED_Z (certInfoMaxLength)int * certInfoLength)1047 int getCertComponentString( INOUT CERT_INFO *certInfoPtr,
1048 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
1049 OUT_BUFFER_OPT( certInfoMaxLength, \
1050 *certInfoLength ) void *certInfo,
1051 IN_LENGTH_SHORT_Z const int certInfoMaxLength,
1052 OUT_LENGTH_BOUNDED_Z( certInfoMaxLength ) \
1053 int *certInfoLength )
1054 {
1055 const void *data = NULL;
1056 int dataLength = 0, status;
1057
1058 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1059 assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
1060 ( certInfo != NULL && \
1061 certInfoMaxLength > 0 && \
1062 certInfoMaxLength < MAX_INTLENGTH_SHORT && \
1063 isWritePtr( certInfo, certInfoMaxLength ) ) );
1064 assert( isWritePtr( certInfoLength, sizeof( int ) ) );
1065
1066 REQUIRES( isAttribute( certInfoType ) || \
1067 isInternalAttribute( certInfoType ) );
1068 REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
1069 ( certInfo != NULL && \
1070 certInfoMaxLength > 0 && \
1071 certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
1072
1073 /* Clear return values */
1074 if( certInfo != NULL )
1075 memset( certInfo, 0, min( 16, certInfoMaxLength ) );
1076 *certInfoLength = 0;
1077
1078 /* If it's a GeneralName or DN component, return it. These are
1079 special-case attribute values so they have to come before the
1080 general attribute-handling code */
1081 if( isGeneralNameComponent( certInfoType ) )
1082 {
1083 SELECTION_STATE selectionState;
1084 ATTRIBUTE_PTR *attributePtr DUMMY_INIT_PTR;
1085 void *dataPtr;
1086
1087 /* Find the requested GeneralName component and return it to the
1088 caller. Since selectGeneralNameComponent() changes the current
1089 selection within the GeneralName, we save the selection state
1090 around the call */
1091 saveSelectionState( selectionState, certInfoPtr );
1092 status = selectGeneralNameComponent( certInfoPtr, certInfoType );
1093 if( cryptStatusOK( status ) )
1094 attributePtr = certInfoPtr->attributeCursor;
1095 restoreSelectionState( selectionState, certInfoPtr );
1096 if( cryptStatusError( status ))
1097 return( status );
1098 ENSURES( attributePtr != NULL );
1099
1100 /* Get the attribute component data */
1101 status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
1102 if( cryptStatusError( status ) )
1103 return( status );
1104 return( attributeCopyParams( certInfo, certInfoMaxLength,
1105 certInfoLength, dataPtr, dataLength ) );
1106 }
1107 if( isDNComponent( certInfoType ) )
1108 {
1109 int count = 0;
1110
1111 /* If this is the currently selected item in the DN, the caller may
1112 be asking for the n-th occurrence rather than the initial one */
1113 if( certInfoPtr->currentSelection.dnComponent == certInfoType )
1114 count = certInfoPtr->currentSelection.dnComponentCount;
1115
1116 /* Find the requested DN component and return it to the caller */
1117 status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
1118 MUST_BE_PRESENT );
1119 if( cryptStatusError( status ) )
1120 return( status );
1121 return( getDNComponentValue( *certInfoPtr->currentSelection.dnPtr,
1122 certInfoType, count, certInfo,
1123 certInfoMaxLength, certInfoLength ) );
1124 }
1125
1126 /* If it's standard certificate or CMS attribute, return it */
1127 if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
1128 certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
1129 ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
1130 certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
1131 {
1132 return( getCertAttributeComponent( certInfoPtr, certInfoType,
1133 certInfo, certInfoMaxLength,
1134 certInfoLength ) );
1135 }
1136
1137 /* If it's anything else, handle it specially */
1138 switch( certInfoType )
1139 {
1140 case CRYPT_CERTINFO_FINGERPRINT_SHA1:
1141 case CRYPT_CERTINFO_FINGERPRINT_SHA2:
1142 case CRYPT_CERTINFO_FINGERPRINT_SHAng:
1143 return( getCertHash( certInfoPtr, certInfoType, certInfo,
1144 certInfoMaxLength, certInfoLength ) );
1145
1146 case CRYPT_CERTINFO_SERIALNUMBER:
1147 switch( certInfoPtr->type )
1148 {
1149 #ifdef USE_CERTREV
1150 case CRYPT_CERTTYPE_CRL:
1151 {
1152 const CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
1153
1154 const REVOCATION_INFO *revInfoPtr = \
1155 ( certRevInfo->currentRevocation != NULL ) ? \
1156 certRevInfo->currentRevocation : certRevInfo->revocations;
1157
1158 if( revInfoPtr != NULL )
1159 {
1160 data = revInfoPtr->id;
1161 dataLength = revInfoPtr->idLength;
1162 }
1163 break;
1164 }
1165 #endif /* USE_CERTREV */
1166
1167 #ifdef USE_CERTREQ
1168 case CRYPT_CERTTYPE_REQUEST_REVOCATION:
1169 data = certInfoPtr->cCertReq->serialNumber;
1170 dataLength = certInfoPtr->cCertReq->serialNumberLength;
1171 break;
1172 #endif /* USE_CERTREQ */
1173
1174 case CRYPT_CERTTYPE_CERTIFICATE:
1175 case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
1176 case CRYPT_CERTTYPE_CERTCHAIN:
1177 data = certInfoPtr->cCertCert->serialNumber;
1178 dataLength = certInfoPtr->cCertCert->serialNumberLength;
1179 break;
1180
1181 default:
1182 retIntError();
1183 }
1184 return( attributeCopyParams( certInfo, certInfoMaxLength,
1185 certInfoLength, data, dataLength ) );
1186
1187 case CRYPT_CERTINFO_VALIDFROM:
1188 case CRYPT_CERTINFO_THISUPDATE:
1189 if( certInfoPtr->startTime > MIN_CERT_TIME_VALUE )
1190 {
1191 data = &certInfoPtr->startTime;
1192 dataLength = sizeof( time_t );
1193 }
1194 return( attributeCopyParams( certInfo, certInfoMaxLength,
1195 certInfoLength, data, dataLength ) );
1196
1197 case CRYPT_CERTINFO_VALIDTO:
1198 case CRYPT_CERTINFO_NEXTUPDATE:
1199 if( certInfoPtr->endTime > MIN_CERT_TIME_VALUE )
1200 {
1201 data = &certInfoPtr->endTime;
1202 dataLength = sizeof( time_t );
1203 }
1204 return( attributeCopyParams( certInfo, certInfoMaxLength,
1205 certInfoLength, data, dataLength ) );
1206
1207 #ifdef USE_CERT_OBSOLETE
1208 case CRYPT_CERTINFO_ISSUERUNIQUEID:
1209 return( attributeCopyParams( certInfo, certInfoMaxLength,
1210 certInfoLength,
1211 certInfoPtr->cCertCert->issuerUniqueID,
1212 certInfoPtr->cCertCert->issuerUniqueIDlength ) );
1213
1214 case CRYPT_CERTINFO_SUBJECTUNIQUEID:
1215 return( attributeCopyParams( certInfo, certInfoMaxLength,
1216 certInfoLength,
1217 certInfoPtr->cCertCert->subjectUniqueID,
1218 certInfoPtr->cCertCert->subjectUniqueIDlength ) );
1219 #endif /* USE_CERT_OBSOLETE */
1220
1221 case CRYPT_CERTINFO_REVOCATIONDATE:
1222 switch( certInfoPtr->type )
1223 {
1224 #ifdef USE_CERTREV
1225 case CRYPT_CERTTYPE_CRL:
1226 case CRYPT_CERTTYPE_OCSP_RESPONSE:
1227 data = getRevocationTimePtr( certInfoPtr );
1228 break;
1229 #endif /* USE_CERTREV */
1230
1231 #ifdef USE_CERTVAL
1232 case CRYPT_CERTTYPE_RTCS_RESPONSE:
1233 data = getValidityTimePtr( certInfoPtr );
1234 break;
1235 #endif /* USE_CERTVAL */
1236
1237 default:
1238 retIntError();
1239 }
1240 if( data != NULL )
1241 dataLength = sizeof( time_t );
1242 return( attributeCopyParams( certInfo, certInfoMaxLength,
1243 certInfoLength, data, dataLength ) );
1244
1245 #ifdef USE_CERT_DNSTRING
1246 case CRYPT_CERTINFO_DN:
1247 {
1248 STREAM stream;
1249
1250 /* Export the entire DN in string form */
1251 status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
1252 MUST_BE_PRESENT );
1253 if( cryptStatusError( status ) )
1254 return( status );
1255 sMemOpenOpt( &stream, certInfo, certInfoMaxLength );
1256 status = writeDNstring( &stream,
1257 *certInfoPtr->currentSelection.dnPtr );
1258 if( cryptStatusOK( status ) )
1259 *certInfoLength = stell( &stream );
1260 sMemDisconnect( &stream );
1261 return( status );
1262 }
1263 #endif /* USE_CERT_DNSTRING */
1264
1265 #ifdef USE_PKIUSER
1266 case CRYPT_CERTINFO_PKIUSER_ID:
1267 case CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD:
1268 case CRYPT_CERTINFO_PKIUSER_REVPASSWORD:
1269 return( getPkiUserInfo( certInfoPtr, certInfoType, certInfo,
1270 certInfoMaxLength, certInfoLength ) );
1271 #endif /* USE_PKIUSER */
1272
1273 #ifdef USE_CERTREV
1274 case CRYPT_IATTRIBUTE_CRLENTRY:
1275 return( getCrlEntry( certInfoPtr, certInfo, certInfoMaxLength,
1276 certInfoLength ) );
1277 #endif /* USE_CERTREV */
1278
1279 case CRYPT_IATTRIBUTE_SUBJECT:
1280 /* Normally these attributes are only present for signed objects
1281 (i.e. ones that are in the high state) but CRMF requests
1282 acting as CMP revocation requests aren't signed so we have to
1283 set the ACLs to allow the attribute to be read in the low
1284 state as well. Since this only represents a programming
1285 error rather than a real access violation we catch it here
1286 with an assertion */
1287 assert( ( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION && \
1288 certInfoPtr->certificate == NULL ) || \
1289 certInfoPtr->certificate != NULL );
1290 return( attributeCopyParams( certInfo, certInfoMaxLength,
1291 certInfoLength,
1292 certInfoPtr->subjectDNptr,
1293 certInfoPtr->subjectDNsize ) );
1294
1295 case CRYPT_IATTRIBUTE_ISSUER:
1296 return( attributeCopyParams( certInfo, certInfoMaxLength,
1297 certInfoLength,
1298 certInfoPtr->issuerDNptr,
1299 certInfoPtr->issuerDNsize ) );
1300
1301 case CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER:
1302 return( getIAndS( certInfoPtr, certInfo, certInfoMaxLength,
1303 certInfoLength ) );
1304
1305 case CRYPT_IATTRIBUTE_HOLDERNAME:
1306 return( getHolderName( certInfoPtr, certInfo, certInfoMaxLength,
1307 certInfoLength ) );
1308
1309 case CRYPT_IATTRIBUTE_HOLDERURI:
1310 return( getHolderURI( certInfoPtr, certInfo, certInfoMaxLength,
1311 certInfoLength ) );
1312
1313 case CRYPT_IATTRIBUTE_SPKI:
1314 {
1315 BYTE *dataStartPtr = certInfo;
1316
1317 status = attributeCopyParams( certInfo, certInfoMaxLength,
1318 certInfoLength,
1319 certInfoPtr->publicKeyInfo,
1320 certInfoPtr->publicKeyInfoSize );
1321 if( cryptStatusError( status ) )
1322 return( status );
1323 if( dataStartPtr != NULL && dataStartPtr[ 0 ] == MAKE_CTAG( 6 ) )
1324 {
1325 /* Fix up CRMF braindamage */
1326 *dataStartPtr = BER_SEQUENCE;
1327 }
1328 return( CRYPT_OK );
1329 }
1330
1331 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
1332 case CRYPT_IATTRIBUTE_RESPONDERURL:
1333 /* An RTCS/OCSP URL may be present if it was copied over from a
1334 certificate that's being checked, however if there wasn't any
1335 authorityInfoAccess information present then the URL won't
1336 have been initialised. Since this attribute isn't accessed
1337 via the normal certificate attribute mechanisms we have to
1338 explictly check for its non-presence */
1339 switch( certInfoPtr->type )
1340 {
1341 #ifdef USE_CERTREV
1342 case CRYPT_CERTTYPE_OCSP_REQUEST:
1343 if( certInfoPtr->cCertRev->responderUrl == NULL )
1344 return( CRYPT_ERROR_NOTFOUND );
1345 return( attributeCopyParams( certInfo, certInfoMaxLength,
1346 certInfoLength,
1347 certInfoPtr->cCertRev->responderUrl,
1348 certInfoPtr->cCertRev->responderUrlSize ) );
1349 #endif /* USE_CERTREV */
1350
1351 #ifdef USE_CERTVAL
1352 case CRYPT_CERTTYPE_RTCS_REQUEST:
1353 if( certInfoPtr->cCertVal->responderUrl == NULL )
1354 return( CRYPT_ERROR_NOTFOUND );
1355 return( attributeCopyParams( certInfo, certInfoMaxLength,
1356 certInfoLength,
1357 certInfoPtr->cCertVal->responderUrl,
1358 certInfoPtr->cCertVal->responderUrlSize ) );
1359 #endif /* USE_CERTVAL */
1360
1361 default:
1362 retIntError();
1363 }
1364 #endif /* USE_CERTREV || USE_CERTVAL */
1365
1366 #ifdef USE_CERTREQ
1367 case CRYPT_IATTRIBUTE_AUTHCERTID:
1368 /* An authorising certificate identifier will be present if
1369 the request was handled by cryptlib but not if it came from
1370 an external source so we have to make sure that there's
1371 something actually present before we try to return it */
1372 if( !memcmp( certInfoPtr->cCertReq->authCertID,
1373 "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) )
1374 return( CRYPT_ERROR_NOTFOUND );
1375 return( attributeCopyParams( certInfo, certInfoMaxLength,
1376 certInfoLength,
1377 certInfoPtr->cCertReq->authCertID,
1378 KEYID_SIZE ) );
1379 #endif /* USE_CERTREQ */
1380
1381 case CRYPT_IATTRIBUTE_ESSCERTID:
1382 return( getESSCertID( certInfoPtr, certInfo, certInfoMaxLength,
1383 certInfoLength ) );
1384 }
1385
1386 retIntError();
1387 }
1388 #endif /* USE_CERTIFICATES */
1389