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