1 /****************************************************************************
2 *																			*
3 *							X.509/PKI Signature Routines					*
4 *						Copyright Peter Gutmann 1993-2007					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "crypt.h"
10   #include "asn1.h"
11   #include "asn1_ext.h"
12   #include "misc_rw.h"
13   #include "mech.h"
14 #else
15   #include "crypt.h"
16   #include "enc_dec/asn1.h"
17   #include "enc_dec/asn1_ext.h"
18   #include "enc_dec/misc_rw.h"
19   #include "mechs/mech.h"
20 #endif /* Compiler-specific includes */
21 
22 #ifdef USE_CERTIFICATES
23 
24 /****************************************************************************
25 *																			*
26 *							X.509-style Signature Functions 				*
27 *																			*
28 ****************************************************************************/
29 
30 /* Create/check an X.509-style signature.  These work with objects of the
31    form:
32 
33 	signedObject ::= SEQUENCE {
34 		object				ANY,
35 		signatureAlgorithm	AlgorithmIdentifier,
36 		signature			BIT STRING
37 		}
38 
39    This is complicated by a variety of b0rken PKI protocols that couldn't
40    quite manage a cut & paste of two lines of text, adding all sorts of
41    unnecessary extra tagging and wrappers to the signature.  These odds and
42    ends are specified in the formatInfo structure */
43 
44 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
createX509signature(OUT_BUFFER (signedObjectMaxLength,* signedObjectLength)void * signedObject,IN_DATALENGTH_Z const int signedObjectMaxLength,OUT_DATALENGTH_Z int * signedObjectLength,IN_BUFFER (objectLength)const void * object,IN_DATALENGTH const int objectLength,IN_HANDLE const CRYPT_CONTEXT iSignContext,IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,IN_OPT const X509SIG_FORMATINFO * formatInfo)45 int createX509signature( OUT_BUFFER( signedObjectMaxLength, \
46 									 *signedObjectLength ) \
47 							void *signedObject,
48 						 IN_DATALENGTH_Z const int signedObjectMaxLength,
49 						 OUT_DATALENGTH_Z int *signedObjectLength,
50 						 IN_BUFFER( objectLength ) const void *object,
51 						 IN_DATALENGTH const int objectLength,
52 						 IN_HANDLE const CRYPT_CONTEXT iSignContext,
53 						 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
54 						 IN_OPT const X509SIG_FORMATINFO *formatInfo )
55 	{
56 	CRYPT_CONTEXT iHashContext;
57 	MESSAGE_CREATEOBJECT_INFO createInfo;
58 	STREAM stream;
59 	BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
60 	int signatureLength, totalSigLength, status;
61 
62 	assert( isWritePtr( signedObject, signedObjectMaxLength ) );
63 	assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
64 	assert( isReadPtr( object, objectLength ) && \
65 			!cryptStatusError( checkObjectEncoding( object, \
66 													objectLength ) ) );
67 	assert( formatInfo == NULL || \
68 			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
69 
70 	REQUIRES( signedObjectMaxLength > MIN_CRYPT_OBJECTSIZE && \
71 			  signedObjectMaxLength < MAX_BUFFER_SIZE );
72 	REQUIRES( objectLength > 0 && objectLength < MAX_BUFFER_SIZE );
73 	REQUIRES( isHandleRangeValid( iSignContext ) );
74 	REQUIRES( isHashAlgo( hashAlgo ) );
75 	REQUIRES( formatInfo == NULL || \
76 			  ( ( formatInfo->tag >= 0 && \
77 				  formatInfo->tag < MAX_CTAG_VALUE ) && \
78 				( formatInfo->extraLength >= 0 && \
79 				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );
80 
81 	/* Clear return values */
82 	memset( signedObject, 0, min( 16, signedObjectMaxLength ) );
83 	*signedObjectLength = 0;
84 
85 	/* Hash the data to be signed */
86 	setMessageCreateObjectInfo( &createInfo, hashAlgo );
87 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
88 							  &createInfo, OBJECT_TYPE_CONTEXT );
89 	if( cryptStatusError( status ) )
90 		return( status );
91 	iHashContext = createInfo.cryptHandle;
92 	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
93 							  ( MESSAGE_CAST ) object, objectLength );
94 	if( cryptStatusOK( status ) )
95 		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
96 	if( cryptStatusError( status ) )
97 		return( status );
98 
99 	/* Create the signature and calculate the overall length of the payload,
100 	   optional signature wrapper, and signature data */
101 	status = createSignature( dataSignature, CRYPT_MAX_PKCSIZE + 128,
102 							  &signatureLength, iSignContext,
103 							  createInfo.cryptHandle, CRYPT_UNUSED,
104 							  SIGNATURE_X509 );
105 	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
106 	if( cryptStatusError( status ) )
107 		return( status );
108 	if( formatInfo == NULL )
109 		totalSigLength = signatureLength;
110 	else
111 		{
112 		/* It's a nonstandard format, figure out the size due to the
113 		   additional signature wrapper and other odds and ends */
114 		totalSigLength = ( int ) \
115 				sizeofObject( signatureLength + formatInfo->extraLength );
116 		if( formatInfo->isExplicit )
117 			totalSigLength = ( int ) sizeofObject( totalSigLength );
118 		}
119 	ENSURES( totalSigLength > 40 && totalSigLength < MAX_BUFFER_SIZE );
120 
121 	/* Make sure that there's enough room for the signed object in the
122 	   output buffer.  This will be checked by the stream handling anyway
123 	   but we make it explicit here */
124 	if( sizeofObject( objectLength + totalSigLength ) > signedObjectMaxLength )
125 		return( CRYPT_ERROR_OVERFLOW );
126 
127 	/* Write the outer SEQUENCE wrapper and copy the payload into place
128 	   behind it */
129 	sMemOpen( &stream, signedObject, signedObjectMaxLength );
130 	writeSequence( &stream, objectLength + totalSigLength );
131 	swrite( &stream, object, objectLength );
132 
133 	/* If it's a nonstandard (b0rken PKI protocol) signature we have to
134 	   kludge in a variety of additional wrappers and other junk around the
135 	   signature */
136 	if( formatInfo != NULL )
137 		{
138 		if( formatInfo->isExplicit )
139 			{
140 			writeConstructed( &stream,
141 							  sizeofObject( signatureLength + \
142 											formatInfo->extraLength ),
143 							  formatInfo->tag );
144 			writeSequence( &stream,
145 						   signatureLength + formatInfo->extraLength );
146 			}
147 		else
148 			{
149 			writeConstructed( &stream,
150 							  signatureLength + formatInfo->extraLength,
151 							  formatInfo->tag );
152 			}
153 		}
154 
155 	/* Finally, append the signature */
156 	status = swrite( &stream, dataSignature, signatureLength );
157 	if( cryptStatusOK( status ) )
158 		*signedObjectLength = stell( &stream );
159 	sMemDisconnect( &stream );
160 	if( cryptStatusError( status ) )
161 		return( status );
162 
163 	assert( ( formatInfo != NULL && formatInfo->extraLength > 0 ) || \
164 			!cryptStatusError( checkObjectEncoding( signedObject, \
165 													*signedObjectLength ) ) );
166 	return( CRYPT_OK );
167 	}
168 
169 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
checkX509signature(IN_BUFFER (signedObjectLength)const void * signedObject,IN_DATALENGTH const int signedObjectLength,IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,IN_OPT const X509SIG_FORMATINFO * formatInfo)170 int checkX509signature( IN_BUFFER( signedObjectLength ) const void *signedObject,
171 						IN_DATALENGTH const int signedObjectLength,
172 						IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
173 						IN_OPT const X509SIG_FORMATINFO *formatInfo )
174 	{
175 	CRYPT_ALGO_TYPE signAlgo, hashAlgo;
176 	CRYPT_CONTEXT iHashContext;
177 	MESSAGE_CREATEOBJECT_INFO createInfo;
178 	STREAM stream;
179 	void *objectPtr DUMMY_INIT_PTR, *sigPtr;
180 	long length;
181 	int sigCheckAlgo, sigLength, hashParam, status;	/* int vs.enum */
182 
183 	assert( isReadPtr( signedObject, signedObjectLength ) );
184 	assert( formatInfo == NULL || \
185 			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
186 
187 	REQUIRES( signedObjectLength > 0 && \
188 			  signedObjectLength < MAX_BUFFER_SIZE );
189 	REQUIRES( isHandleRangeValid( iSigCheckContext ) );
190 	REQUIRES( formatInfo == NULL || \
191 			  ( ( formatInfo->tag >= 0 && \
192 				  formatInfo->tag < MAX_CTAG_VALUE ) && \
193 				( formatInfo->extraLength >= 0 && \
194 				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );
195 
196 	/* Make sure that the signing parameters are in order */
197 	status = krnlSendMessage( iSigCheckContext, IMESSAGE_GETATTRIBUTE,
198 							  &sigCheckAlgo, CRYPT_CTXINFO_ALGO );
199 	if( cryptStatusError( status ) )
200 		return( status );
201 
202 	/* Check the start of the object and record the start and size of the
203 	   encapsulated signed object.  We have to use the long-length form of
204 	   the length functions to handle mega-CRLs */
205 	sMemConnect( &stream, signedObject, signedObjectLength );
206 	readLongSequence( &stream, NULL );
207 	status = getLongStreamObjectLength( &stream, &length );
208 	if( cryptStatusOK( status ) )
209 		status = sMemGetDataBlock( &stream, &objectPtr, length );
210 	if( cryptStatusOK( status ) )
211 		status = sSkip( &stream, length, SSKIP_MAX );
212 	if( cryptStatusError( status ) )
213 		{
214 		sMemDisconnect( &stream );
215 		return( status );
216 		}
217 
218 	/* If it's a broken signature, process the extra encapsulation */
219 	if( formatInfo != NULL )
220 		{
221 		if( formatInfo->isExplicit )
222 			{
223 			readConstructed( &stream, NULL, formatInfo->tag );
224 			status = readSequence( &stream, NULL );
225 			}
226 		else
227 			status = readConstructed( &stream, NULL, formatInfo->tag );
228 		if( cryptStatusError( status ) )
229 			{
230 			sMemDisconnect( &stream );
231 			return( status );
232 			}
233 		}
234 
235 	/* Remember the location and size of the signature data */
236 	status = sMemGetDataBlockRemaining( &stream, &sigPtr, &sigLength );
237 	if( cryptStatusError( status ) )
238 		{
239 		sMemDisconnect( &stream );
240 		return( status );
241 		}
242 	status = readAlgoIDex( &stream, &signAlgo, &hashAlgo, &hashParam,
243 						   ALGOID_CLASS_PKCSIG );
244 	sMemDisconnect( &stream );
245 	if( cryptStatusError( status ) )
246 		return( status );
247 	ANALYSER_HINT( sigPtr != NULL );
248 
249 	/* If the signature algorithm isn't what we expected the best that we
250 	   can do is report a signature error */
251 	if( sigCheckAlgo != signAlgo )
252 		return( CRYPT_ERROR_SIGNATURE );
253 
254 	/* Create a hash context from the algorithm identifier of the
255 	   signature */
256 	setMessageCreateObjectInfo( &createInfo, hashAlgo );
257 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
258 							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
259 							  OBJECT_TYPE_CONTEXT );
260 	if( cryptStatusError( status ) )
261 		return( status );
262 	iHashContext = createInfo.cryptHandle;
263 	if( hashParam != 0 )
264 		{
265 		/* Some hash algorithms have variable output size, in which case
266 		   we need to explicitly tell the context which one we're working
267 		   with */
268 		status = krnlSendMessage( iHashContext, IMESSAGE_SETATTRIBUTE,
269 								  &hashParam, CRYPT_CTXINFO_BLOCKSIZE );
270 		if( cryptStatusError( status ) )
271 			return( status );
272 		}
273 
274 	/* Hash the signed data and check the signature on the object */
275 	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
276 							  objectPtr, length );
277 	if( cryptStatusOK( status ) )
278 		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
279 								  "", 0 );
280 	if( cryptStatusOK( status ) )
281 		{
282 		status = checkSignature( sigPtr, sigLength, iSigCheckContext,
283 								 iHashContext, CRYPT_UNUSED,
284 								 SIGNATURE_X509 );
285 		}
286 	krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
287 
288 	return( status );
289 	}
290 
291 /****************************************************************************
292 *																			*
293 *							PKI Protocol Signature Functions 				*
294 *																			*
295 ****************************************************************************/
296 
297 /* The various PKIX certificate management protocols are built using the
298    twin design guidelines that nothing should use a standard style of
299    signature and no two protocols should use the same nonstandard format,
300    the only way to handle these (without creating dozens of new signature
301    types, each with their own special-case handling) is to process most of
302    the signature information at the protocol level and just check the raw
303    signature here */
304 
305 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
createRawSignature(OUT_BUFFER (sigMaxLength,* signatureLength)void * signature,IN_LENGTH_SHORT_MIN (MIN_CRYPT_OBJECTSIZE)const int sigMaxLength,OUT_LENGTH_BOUNDED_Z (sigMaxLength)int * signatureLength,IN_HANDLE const CRYPT_CONTEXT iSignContext,IN_HANDLE const CRYPT_CONTEXT iHashContext)306 int createRawSignature( OUT_BUFFER( sigMaxLength, *signatureLength ) \
307 							void *signature,
308 						IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
309 							const int sigMaxLength,
310 						OUT_LENGTH_BOUNDED_Z( sigMaxLength ) \
311 							int *signatureLength,
312 						IN_HANDLE const CRYPT_CONTEXT iSignContext,
313 						IN_HANDLE const CRYPT_CONTEXT iHashContext )
314 	{
315 	assert( isWritePtr( signature, sigMaxLength ) );
316 	assert( isWritePtr( signatureLength, sizeof( int ) ) );
317 
318 	REQUIRES( sigMaxLength >= MIN_CRYPT_OBJECTSIZE && \
319 			  sigMaxLength < MAX_INTLENGTH_SHORT );
320 	REQUIRES( isHandleRangeValid( iSignContext ) );
321 	REQUIRES( isHandleRangeValid( iHashContext ) );
322 
323 	return( createSignature( signature, sigMaxLength, signatureLength,
324 							 iSignContext, iHashContext, CRYPT_UNUSED,
325 							 SIGNATURE_RAW ) );
326 	}
327 
328 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
checkRawSignature(IN_BUFFER (signatureLength)const void * signature,IN_LENGTH_SHORT const int signatureLength,IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,IN_HANDLE const CRYPT_CONTEXT iHashContext)329 int checkRawSignature( IN_BUFFER( signatureLength ) const void *signature,
330 					   IN_LENGTH_SHORT const int signatureLength,
331 					   IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
332 					   IN_HANDLE const CRYPT_CONTEXT iHashContext )
333 	{
334 	assert( isReadPtr( signature, signatureLength ) );
335 
336 	REQUIRES( signatureLength > 0 && signatureLength < MAX_INTLENGTH_SHORT );
337 	REQUIRES( isHandleRangeValid( iSigCheckContext ) );
338 	REQUIRES( isHandleRangeValid( iHashContext ) );
339 
340 	return( checkSignature( signature, signatureLength, iSigCheckContext,
341 							iHashContext, CRYPT_UNUSED, SIGNATURE_RAW ) );
342 	}
343 #endif /* USE_CERTIFICATES */
344