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