cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
env_attr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Envelope Attribute Routines *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include "crypt.h"
9 #ifdef INC_ALL
10  #include "envelope.h"
11 #else
12  #include "envelope/envelope.h"
13 #endif /* Compiler-specific includes */
14 
15 #ifdef USE_ENVELOPES
16 
17 /****************************************************************************
18 * *
19 * Utility Functions *
20 * *
21 ****************************************************************************/
22 
23 /* Exit after setting extended error information */
24 
26 static int exitError( INOUT ENVELOPE_INFO *envelopeInfoPtr,
27  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
28  IN_ENUM( CRYPT_ERRTYPE ) const CRYPT_ERRTYPE_TYPE errorType,
29  IN_ERROR const int status )
30  {
31  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
32 
33  REQUIRES( isAttribute( errorLocus ) || \
34  isInternalAttribute( errorLocus ) );
35  REQUIRES( errorType > CRYPT_ERRTYPE_NONE && \
36  errorType < CRYPT_ERRTYPE_LAST );
37  REQUIRES( cryptStatusError( status ) );
38 
39  setErrorInfo( envelopeInfoPtr, errorLocus, errorType );
40  return( status );
41  }
42 
44 static int exitErrorInited( INOUT ENVELOPE_INFO *envelopeInfoPtr,
45  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
46  {
47  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
48 
49  REQUIRES( isAttribute( errorLocus ) || \
50  isInternalAttribute( errorLocus ) );
51 
52  return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
54  }
55 
57 static int exitErrorNotInited( INOUT ENVELOPE_INFO *envelopeInfoPtr,
58  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
59  {
60  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
61 
62  REQUIRES( isAttribute( errorLocus ) || \
63  isInternalAttribute( errorLocus ) );
64 
65  return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
67  }
68 
70 static int exitErrorNotFound( INOUT ENVELOPE_INFO *envelopeInfoPtr,
71  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
72  {
73  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
74 
75  REQUIRES( isAttribute( errorLocus ) || \
76  isInternalAttribute( errorLocus ) );
77 
78  return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
80  }
81 
82 /* Reset the internal virtual cursor in a content-list item after we've
83  moved the attribute cursor */
84 
85 STDC_NONNULL_ARG( ( 1 ) ) \
86 static void resetVirtualCursor( INOUT CONTENT_LIST *contentListPtr )
87  {
88  assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
89 
90  if( contentListPtr->type != CONTENT_SIGNATURE )
91  return;
92  contentListPtr->clSigInfo.attributeCursorEntry = \
93  CRYPT_ENVINFO_SIGNATURE_RESULT;
94  }
95 
96 /* Move the internal virtual cursor within a content-list item */
97 
99 static BOOLEAN moveVirtualCursor( INOUT CONTENT_LIST *contentListPtr,
100  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType )
101  {
102  static const CRYPT_ATTRIBUTE_TYPE attributeOrderList[] = {
105  CRYPT_ATTRIBUTE_NONE, CRYPT_ATTRIBUTE_NONE };
106  CONTENT_SIG_INFO *sigInfo = &contentListPtr->clSigInfo;
108  BOOLEAN doContinue;
109  int iterationCount;
110 
111  assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
112 
113  REQUIRES( attrGetType == ATTR_NEXT || attrGetType == ATTR_PREV );
115 
116  for( doContinue = TRUE, iterationCount = 0;
117  doContinue && iterationCount < FAILSAFE_ITERATIONS_SMALL;
118  iterationCount++ )
119  {
120  int i;
121 
122  /* Find the position of the current sub-attribute in the attribute
123  order list and use that to get its successor/predecessor sub-
124  attribute */
125  for( i = 0;
126  attributeOrderList[ i ] != attributeType && \
127  attributeOrderList[ i ] != CRYPT_ATTRIBUTE_NONE && \
128  i < FAILSAFE_ARRAYSIZE( attributeOrderList, CRYPT_ATTRIBUTE_TYPE );
129  i++ );
130  ENSURES( i < FAILSAFE_ARRAYSIZE( attributeOrderList, \
132  if( attributeOrderList[ i ] == CRYPT_ATTRIBUTE_NONE )
133  {
134  /* We've reached the first/last sub-attribute within the current
135  item/group, tell the caller that there are no more sub-
136  attributes present and they have to move on to the next
137  group */
138  return( FALSE );
139  }
140  if( attrGetType == ATTR_PREV )
141  attributeType = ( i < 1 ) ? CRYPT_ATTRIBUTE_NONE : \
142  attributeOrderList[ i - 1 ];
143  else
144  attributeType = attributeOrderList[ i + 1 ];
145  if( attributeType == CRYPT_ATTRIBUTE_NONE )
146  {
147  /* We've reached the first/last sub-attribute within the current
148  item/group, exit as before */
149  return( FALSE );
150  }
151 
152  /* Check whether the required sub-attribute is present. If not, we
153  continue and try the next one */
154  doContinue = FALSE;
155  switch( attributeType )
156  {
158  break; /* Always present */
159 
161  if( sigInfo->iSigCheckKey == CRYPT_ERROR )
162  doContinue = TRUE;
163  break;
164 
166  if( sigInfo->iExtraData == CRYPT_ERROR )
167  doContinue = TRUE;
168  break;
169 
171  if( sigInfo->iTimestamp == CRYPT_ERROR )
172  doContinue = TRUE;
173  break;
174 
175  default:
177  }
178  }
179  ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );
181 
182  return( TRUE );
183  }
184 
185 /* Callback function used to provide external access to content list-
186  internal fields */
187 
188 CHECK_RETVAL_PTR \
189 static const void *getAttrFunction( IN_OPT TYPECAST( CONTENT_LIST * ) \
190  const void *attributePtr,
192  CRYPT_ATTRIBUTE_TYPE *groupID,
196  CRYPT_ATTRIBUTE_TYPE *instanceID,
197  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType )
198  {
199  CONTENT_LIST *contentListPtr = ( CONTENT_LIST * ) attributePtr;
200  BOOLEAN subGroupMove;
201 
202  assert( contentListPtr == NULL || \
203  isReadPtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
204  assert( groupID == NULL || \
205  isWritePtr( groupID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
206  assert( attributeID == NULL || \
207  isWritePtr( attributeID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
208  assert( instanceID == NULL || \
209  isWritePtr( instanceID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
210 
211  REQUIRES_N( attrGetType > ATTR_NONE && attrGetType < ATTR_LAST );
212 
213  /* Clear return values */
214  if( groupID != NULL )
215  *groupID = CRYPT_ATTRIBUTE_NONE;
216  if( attributeID != NULL )
217  *attributeID = CRYPT_ATTRIBUTE_NONE;
218  if( instanceID != NULL )
219  *instanceID = CRYPT_ATTRIBUTE_NONE;
220 
221  /* Move to the next or previous attribute if required. This isn't just a
222  case of following the prev/next links because some content-list items
223  contain an entire attribute group so positioning by attribute within
224  these only changes the current selection within the group (== content-
225  list item) rather than moving to the previous/next entry. Because of
226  this we have to special-case the code for composite items (currently
227  only signature objects meet this definition) and allow virtual
228  positioning within the item */
229  if( contentListPtr == NULL )
230  return( NULL );
231  subGroupMove = ( ( attrGetType == ATTR_PREV || \
232  attrGetType == ATTR_NEXT ) && \
233  ( contentListPtr->type == CONTENT_SIGNATURE ) ) ? \
234  TRUE : FALSE;
235  if( subGroupMove )
236  subGroupMove = moveVirtualCursor( contentListPtr, attrGetType );
237 
238  /* If we're moving by group, move to the next/previous content list
239  item and reset the internal virtual cursor. Note that we always
240  advance the cursor to the next/prev attribute, it's up to the calling
241  code to manage attribute by attribute vs.group by group moves */
242  if( !subGroupMove && attrGetType != ATTR_CURRENT )
243  {
244  contentListPtr = ( attrGetType == ATTR_PREV ) ? \
245  contentListPtr->prev : contentListPtr->next;
246  if( contentListPtr != NULL )
247  resetVirtualCursor( contentListPtr );
248  }
249  if( contentListPtr == NULL )
250  return( NULL );
251 
252  /* Return ID information to the caller. We only return the group ID if
253  we've moved within the attribute group, if we've moved from one group
254  to another we leave it cleared because envelopes can contain multiple
255  groups with the same ID and returning an ID identical to the one from
256  the group that we've moved out of would make it look as if we're still
257  within the same group. Note that this relies on the behaviour of the
258  attribute-move functions, which first get the current group using
259  ATTR_CURRENT and then move to the next or previous using ATTR_NEXT/
260  PREV */
261  if( groupID != NULL && ( attrGetType == ATTR_CURRENT || subGroupMove ) )
262  *groupID = contentListPtr->envInfo;
263  if( attributeID != NULL && contentListPtr->type == CONTENT_SIGNATURE )
264  *attributeID = contentListPtr->clSigInfo.attributeCursorEntry;
265  return( contentListPtr );
266  }
267 
268 /* Instantiate a certificate chain from a collection of certificates */
269 
270 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
271 static int instantiateCertChain( INOUT CONTENT_LIST *contentListItem,
272  IN_BUFFER( certChainDataLength ) \
273  const void *certChainData,
275  const int certChainDataLength )
276  {
277  MESSAGE_CREATEOBJECT_INFO createInfo;
278  int status;
279 
280  assert( isWritePtr( contentListItem, sizeof( CONTENT_LIST ) ) );
281  assert( isReadPtr( certChainData, certChainDataLength ) );
282 
283  REQUIRES( contentListItem->type == CONTENT_SIGNATURE );
284  REQUIRES( certChainDataLength >= MIN_CRYPT_OBJECTSIZE && \
285  certChainDataLength < MAX_INTLENGTH_SHORT );
286 
287  /* Instantiate the certificate chain. Since this isn't a true
288  certificate chain (in the sense of being degenerate PKCS #7
289  SignedData) but only a context-tagged SET OF Certificate, we notify
290  the certificate management code of this when it performs the import */
291  setMessageCreateObjectIndirectInfo( &createInfo, certChainData,
292  certChainDataLength, CRYPT_ICERTTYPE_CMS_CERTSET );
293  if( contentListItem->issuerAndSerialNumber == NULL )
294  {
295  createInfo.arg2 = CRYPT_IKEYID_KEYID;
296  createInfo.strArg2 = contentListItem->keyID;
297  createInfo.strArgLen2 = contentListItem->keyIDsize;
298  }
299  else
300  {
301  createInfo.arg2 = CRYPT_IKEYID_ISSUERANDSERIALNUMBER;
302  createInfo.strArg2 = contentListItem->issuerAndSerialNumber;
303  createInfo.strArgLen2 = contentListItem->issuerAndSerialNumberSize;
304  }
307  &createInfo, OBJECT_TYPE_CERTIFICATE );
308  if( cryptStatusOK( status ) )
309  contentListItem->clSigInfo.iSigCheckKey = createInfo.cryptHandle;
310  return( status );
311  }
312 
313 /* Get information on the attribute at the current attribute-cursor
314  position. This isn't quite as simple as it sounds because trying to
315  obtain the info may require a decrypt or key-import operation in order
316  to obtain it */
317 
318 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
319 static int getCurrentAttributeInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
320  OUT_INT_Z int *valuePtr )
321  {
322  CONTENT_LIST *contentListItem = envelopeInfoPtr->contentListCurrent;
323  MESSAGE_KEYMGMT_INFO getkeyInfo;
324  int status;
325 
326  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
327  assert( isWritePtr( valuePtr, sizeof( int ) ) );
328 
329  REQUIRES( contentListItem != NULL );
330 
331  /* Clear return value */
332  *valuePtr = 0;
333 
334  /* If we need something other than a private key or we need a private
335  key but there's no keyset present to fetch it from, just report what
336  we need and exit */
337  if( contentListItem->envInfo != CRYPT_ENVINFO_PRIVATEKEY || \
338  envelopeInfoPtr->iDecryptionKeyset == CRYPT_ERROR )
339  {
340  *valuePtr = contentListItem->envInfo;
341  return( CRYPT_OK );
342  }
343 
344  /* There's a decryption keyset available, try and get the required key
345  from it. Even though we're accessing the key by (unique) key ID we
346  still specify the key type preference in case there's some problem
347  with the ID info. This means that we return a more meaningful error
348  message now rather than a usage-related one when we try to use the
349  key.
350 
351  Unlike signature check keyset access, we retry the access every time
352  we're called because we may be talking to a device that has a trusted
353  authentication path which is outside our control so that the first
354  read fails if the user hasn't entered their PIN but a second read
355  once they've entered it will succeed */
356  if( contentListItem->issuerAndSerialNumber == NULL )
357  {
358  setMessageKeymgmtInfo( &getkeyInfo,
359  ( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
360  CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
361  contentListItem->keyID, contentListItem->keyIDsize,
362  NULL, 0, KEYMGMT_FLAG_USAGE_CRYPT );
363  }
364  else
365  {
366  setMessageKeymgmtInfo( &getkeyInfo,
367  CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
368  contentListItem->issuerAndSerialNumber,
369  contentListItem->issuerAndSerialNumberSize,
370  NULL, 0, KEYMGMT_FLAG_USAGE_CRYPT );
371  }
372  status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
373  IMESSAGE_KEY_GETKEY, &getkeyInfo,
375  if( cryptArgError( status ) )
376  {
377  /* Make sure that any argument errors arising from this internal key
378  fetch don't get propagated back up to the caller. Note that this
379  error is converted to a CRYPT_OK later on (see the comment further
380  down) but we perform the cleanup here to keep things tidy */
381  status = CRYPT_ERROR_NOTFOUND;
382  }
383 
384  /* If we managed to get the private key (either bcause it wasn't
385  protected by a password if it's in a keyset or because it came from a
386  device), push it into the envelope. If the call succeeds this will
387  import the session key and delete the required-information list.
388 
389  What to do when this operation fails is a bit tricky since the
390  supposedly idempotent step of reading an attribute can have side-
391  effects if it results in a key being read from a crypto device that
392  in turn is used to import a wrapped session key. Changing the
393  externally-visible behaviour isn't really an option because the
394  import is normally triggered by the addition of unwrap keying
395  material but in this case it's already present, and the caller has
396  nothing to add to trigger the import. Conversely though it's a bit
397  confusing to report side-effects of the (invisible) key-unwrap
398  process to the caller in response to an attribute read. However,
399  masking the details entirely can lead the caller down a blind alley
400  in which they apparently need to add an unwrap key but it's already
401  been added via the device and the unwrap process failed.
402 
403  A compromise solution is to select the return values the definitely
404  indicate that there's no chance of continuing and report those, and
405  otherwise to indicate that an unwrap key is needed. The only return
406  value that's really a ne pas ultra in this case is
407  CRYPT_ERROR_BADDATA, all others are potentially recoverable or at
408  least misleading if returned in this context (for example
409  CRYPT_ERROR_NOTAVAIL interpreted in the context of read-current-
410  attribute has a very different meaning than in the context of unwrap-
411  key) */
412  if( cryptStatusOK( status ) )
413  {
414  status = envelopeInfoPtr->addInfo( envelopeInfoPtr,
416  getkeyInfo.cryptHandle );
418  if( status == CRYPT_ERROR_BADDATA )
419  {
420  /* We've reached a cant-continue condition, report it to the
421  caller */
422  *valuePtr = CRYPT_ATTRIBUTE_NONE;
423  return( CRYPT_ERROR_BADDATA );
424  }
425  }
426 
427  /* If we got the key, there's nothing else needed. If we didn't we still
428  return an OK status since the caller is asking us for the resource
429  which is required and not the status of any background operation that
430  was performed while trying to obtain it */
431  *valuePtr = cryptStatusError( status ) ? \
432  envelopeInfoPtr->contentListCurrent->envInfo : \
433  CRYPT_ATTRIBUTE_NONE;
434  return( CRYPT_OK );
435  }
436 
437 /* Get the result of the signature-check process and the key used for
438  signing. Since the signature check is performed on-demand this can
439  require a considerable amount of additional work */
440 
441 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
442 static int getSignatureResult( INOUT ENVELOPE_INFO *envelopeInfoPtr,
443  OUT_INT_Z int *valuePtr )
444  {
446  const CONTENT_SIG_INFO *sigInfo;
447  CONTENT_LIST *contentListItem = envelopeInfoPtr->contentListCurrent;
448  MESSAGE_KEYMGMT_INFO getkeyInfo;
449  int status;
450 
451  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
452  assert( isWritePtr( valuePtr, sizeof( int ) ) );
453 
454  REQUIRES( envelopeInfoPtr->usage == ACTION_MAC || \
455  ( envelopeInfoPtr->usage == ACTION_CRYPT && \
456  ( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) ) || \
457  contentListItem != NULL );
458 
459  /* Clear return value */
460  *valuePtr = 0;
461 
462  /* If it's a MACd or authenticated-encrypted envelope then the signature
463  result isn't held in a content list as for the other signatures since
464  the "signature" is just a MAC tag appended to the data. The
465  appropriate value to return here is a bit tricky since an attacker
466  could corrupt the MAC tag and force a less severe error like
467  CRYPT_ERROR_UNDERFLOW (by truncating the data). However we can only
468  get here once we've reached the finished state, which means that all
469  of the data (including the MAC tag) has been successfully processed.
470  This means that any persistent error state is regarded as the
471  equivalent of a signature error */
472  if( envelopeInfoPtr->usage == ACTION_MAC || \
473  ( envelopeInfoPtr->usage == ACTION_CRYPT && \
474  ( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) ) )
475  {
476  *valuePtr = ( envelopeInfoPtr->errorState != CRYPT_OK ) ? \
478  return( CRYPT_OK );
479  }
480 
481  REQUIRES( contentListItem != NULL );
482 
483  /* Make sure that the content list item is of the appropriate type, and
484  if we've already done this one don't process it a second time. This
485  check is also performed by the addInfo() code but we duplicate it
486  here (just for the signature-result attribute) to avoid having to do
487  an unnecessary key fetch for non-CMS signatures */
488  sigInfo = &contentListItem->clSigInfo;
489  if( contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE )
490  return( exitErrorNotFound( envelopeInfoPtr,
492  if( contentListItem->flags & CONTENTLIST_PROCESSED )
493  {
494  *valuePtr = sigInfo->processingResult;
495  return( CRYPT_OK );
496  }
497 
498  /* If there's an encoded certificate chain present and it hasn't been
499  instantiated as a certificate object yet, instantiate it now. We
500  don't check the return value since a failure isn't fatal, we can
501  still perform the signature check with a key pulled from a keyset */
502  if( sigInfo->iSigCheckKey == CRYPT_ERROR && \
503  envelopeInfoPtr->auxBuffer != NULL )
504  {
505  ( void ) instantiateCertChain( contentListItem,
506  envelopeInfoPtr->auxBuffer,
507  envelopeInfoPtr->auxBufSize );
508  }
509 
510  /* If we have a key instantiated from a certificate chain, use that to
511  check the signature. In theory we could also be re-using the key
512  from an earlier, not-completed check, however this is only retained
513  if the check succeeds (to allow a different key to be tried if the
514  check fails) so in practice this never occurs */
515  if( sigInfo->iSigCheckKey != CRYPT_ERROR )
516  {
517  /* Add the signature-check key with the special type
518  CRYPT_ENVINFO_SIGNATURE_RESULT to indicate that it's been
519  provided internally rather than being supplied by the user */
520  *valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
522  sigInfo->iSigCheckKey );
523  return( CRYPT_OK );
524  }
525 
526  /* We don't have a signature check key available (for example from a CMS
527  certificate chain), make sure that there's a keyset available to pull
528  the key from and get the key from it */
529  if( envelopeInfoPtr->iSigCheckKeyset == CRYPT_ERROR )
530  return( exitErrorNotInited( envelopeInfoPtr,
532 
533  /* Try and get the required key. Even though we're accessing the key by
534  (unique) key ID we still specify the key type preference in case
535  there's some problem with the ID info. This means that we return a
536  more meaningful error message now rather than a usage-related one
537  when we try to use the key */
538  if( contentListItem->issuerAndSerialNumber == NULL )
539  {
540  setMessageKeymgmtInfo( &getkeyInfo,
541  ( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
542  CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
543  contentListItem->keyID, contentListItem->keyIDsize,
544  NULL, 0, KEYMGMT_FLAG_USAGE_SIGN );
545  }
546  else
547  {
548  setMessageKeymgmtInfo( &getkeyInfo,
549  CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
550  contentListItem->issuerAndSerialNumber,
551  contentListItem->issuerAndSerialNumberSize,
552  NULL, 0, KEYMGMT_FLAG_USAGE_SIGN );
553  }
554  status = krnlSendMessage( envelopeInfoPtr->iSigCheckKeyset,
555  IMESSAGE_KEY_GETKEY, &getkeyInfo,
557  if( cryptStatusError( status ) )
558  {
559  retExtObj( status,
560  ( status, ENVELOPE_ERRINFO,
561  envelopeInfoPtr->iSigCheckKeyset,
562  "Couldn't retrieve signature-check key from keyset" ) );
563  }
564  iCryptHandle = getkeyInfo.cryptHandle;
565 
566  /* Push the public key into the envelope, which performs the signature
567  check. Adding the key increments its reference count since the key
568  is usually user-supplied and we need to keep a reference for use by
569  the envelope, however since the key that we're using here is an
570  internal-use-only key we don't want to do this so we decrement it
571  again after it's been added. In addition we add the signature-check
572  key with the special type CRYPT_ENVINFO_SIGNATURE_RESULT to indicate
573  that it's been provided internally rather than being user-supplied */
574  *valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
576  iCryptHandle );
577  krnlSendNotifier( iCryptHandle, IMESSAGE_DECREFCOUNT );
578 
579  /* If the key wasn't used for the signature check (i.e. it wasn't stored
580  in the content list for later use, which means it isn't needed any
581  more), discard it */
582  if( sigInfo->iSigCheckKey == CRYPT_ERROR )
583  krnlSendNotifier( iCryptHandle, IMESSAGE_DECREFCOUNT );
584 
585  return( CRYPT_OK );
586  }
587 
588 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
589 static int getSignatureKey( INOUT ENVELOPE_INFO *envelopeInfoPtr,
590  OUT_INT_Z int *valuePtr )
591  {
592  CRYPT_CERTIFICATE sigCheckCert;
593  CONTENT_LIST *contentListItem = envelopeInfoPtr->contentListCurrent;
594  CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
595  int status;
596 
597  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
598  assert( isWritePtr( valuePtr, sizeof( int ) ) );
599 
600  REQUIRES( contentListItem != NULL );
601 
602  /* Clear return value */
603  *valuePtr = 0;
604 
605  /* If there's no signing key present try and instantiate it from an
606  attached certificate chain */
607  if( sigInfo->iSigCheckKey == CRYPT_ERROR )
608  {
609  if( envelopeInfoPtr->auxBuffer == NULL )
610  {
611  /* There's no attached certificate chain to recover the signing
612  key from, we can't go any further */
613  return( exitErrorNotFound( envelopeInfoPtr,
615  }
616  status = instantiateCertChain( contentListItem,
617  envelopeInfoPtr->auxBuffer,
618  envelopeInfoPtr->auxBufSize );
619  if( cryptStatusError( status ) )
620  return( exitError( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
621  CRYPT_ERRTYPE_ATTR_VALUE, status ) );
622  }
623 
624  /* If we instantiated the signature-check key ourselves (either from a
625  keyset or from envelope data) rather than having it supplied
626  externally, we're done */
627  if( !( contentListItem->flags & CONTENTLIST_EXTERNALKEY ) )
628  {
630  *valuePtr = sigInfo->iSigCheckKey;
631 
632  return( CRYPT_OK );
633  }
634 
635  /* The signature check key was externally supplied by the caller. If
636  they added a private key+certificate combination as the signature
637  check key then this will return a supposed signature-check
638  certificate that actually has private-key capabilities. Even adding
639  a simple certificate (+ public key context for the signature check)
640  can be dangerous since it can act as a subliminal channel if it's
641  passed on to a different user (although exactly how this would be
642  exploitable is another question entirely). To avoid this problem we
643  completely isolate the added signature check key by returning a copy
644  of the associated certificate object */
646  &sigCheckCert, CRYPT_IATTRIBUTE_CERTCOPY );
647  if( cryptStatusError( status ) )
648  return( exitError( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
649  CRYPT_ERRTYPE_ATTR_VALUE, status ) );
650 
651  /* We've created a new instantiation of the signature check key which is
652  distinct from the externally-supplied original, replace the existing
653  one with the new one and return it to the caller */
655  *valuePtr = sigInfo->iSigCheckKey = sigCheckCert;
656 
657  return( CRYPT_OK );
658  }
659 
660 /* Check an attribute add that isn't handled by the table-driven
661  general-purpose checks in setContextAttribute() */
662 
663 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 5 ) ) \
664 static int checkOtherAttribute( INOUT ENVELOPE_INFO *envelopeInfoPtr,
665  IN_INT_Z const int value,
667  OUT_ENUM_OPT( ACTION ) ACTION_TYPE *usage,
669  MESSAGE_CHECK_TYPE *checkType )
670  {
671  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
672  assert( isWritePtr( usage, sizeof( ACTION_TYPE ) ) );
673 
674  REQUIRES( value >= 0 && value < MAX_INTLENGTH );
675  REQUIRES( isAttribute( attribute ) || \
676  isInternalAttribute( attribute ) );
677 
678  /* Clear return values */
679  *usage = ACTION_NONE;
680  *checkType = MESSAGE_CHECK_NONE;
681 
682  switch( attribute )
683  {
685  if( !envelopeInfoPtr->checkAlgo( value,
686  isStreamCipher( value ) ? CRYPT_MODE_OFB : \
687  ( envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) ? \
689  return( CRYPT_ARGERROR_VALUE );
690  envelopeInfoPtr->defaultAlgo = value;
691  return( OK_SPECIAL );
692 
694  if( !envelopeInfoPtr->checkAlgo( value, CRYPT_MODE_NONE ) )
695  return( CRYPT_ARGERROR_VALUE );
696  envelopeInfoPtr->defaultHash = value;
697  return( OK_SPECIAL );
698 
700  if( !envelopeInfoPtr->checkAlgo( value, CRYPT_MODE_NONE ) )
701  return( CRYPT_ARGERROR_VALUE );
702  envelopeInfoPtr->defaultMAC = value;
703  return( OK_SPECIAL );
704 
706  if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
707  return( exitErrorInited( envelopeInfoPtr,
709  return( CRYPT_OK );
710 
712  /* Exactly what's supposed to happen when PGP is asked to sign
713  non-plain-data is ill-defined. No command-line PGP option
714  will generate this type of message, and the RFCs don't
715  specify the behaviour (in fact RFC 1991's description of PGP
716  signing is completely wrong). In practice PGP hashes and
717  signs the payload contents of a PGP literal data packet,
718  however if there are extra layers of processing between the
719  signing and literal packets (e.g. compression or encryption)
720  then what gets hashed isn't specified. If it's always the
721  payload of the final (literal) data packet we'd have to be
722  able to burrow down through arbitrary amounts of further data
723  and processing in order to get to the payload data to hash
724  (this also makes things like mail gateways that only allow
725  signed messages through infeasible unless the gateway holds
726  everyone's private key in order to get at the plaintext to
727  hash). Because of this problem we disallow any attempts to
728  set a content-type other than plain data if we're signing a
729  PGP-format message */
730  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
731  envelopeInfoPtr->usage == ACTION_SIGN && \
732  value != CRYPT_CONTENT_DATA )
733  return( CRYPT_ARGERROR_VALUE );
734 
735  /* For user-friendliness we allow overwriting a given content
736  type with the same type, which is useful for cases when
737  cryptlib automatically presets the type based on other
738  information */
739  if( envelopeInfoPtr->contentType && \
740  envelopeInfoPtr->contentType != value )
741  return( exitErrorInited( envelopeInfoPtr,
743  return( CRYPT_OK );
744 
746  /* The integrity-protection flag can't be reset to a value of
747  CRYPT_INTEGRITY_NONE once it's been set to a higher level.
748  If it could be reset then the caller could set non-MAC-
749  compatible options by clearing the flag and then setting it
750  again afterwards */
751  if( envelopeInfoPtr->usage != ACTION_NONE )
752  return( CRYPT_ERROR_INITED );
753  return( CRYPT_OK );
754 
756  *checkType = ( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) ? \
759  if( envelopeInfoPtr->usage != ACTION_NONE && \
760  envelopeInfoPtr->usage != ACTION_SIGN )
761  return( exitErrorInited( envelopeInfoPtr,
763  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
764  envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
765  {
766  /* See the long comment for CRYPT_ENVINFO_CONTENTTYPE */
767  return( CRYPT_ARGERROR_VALUE );
768  }
769  *usage = ACTION_SIGN;
770  return( CRYPT_OK );
771 
773  if( envelopeInfoPtr->type != CRYPT_FORMAT_CMS && \
774  envelopeInfoPtr->type != CRYPT_FORMAT_SMIME )
775  return( CRYPT_ARGERROR_VALUE );
776  if( envelopeInfoPtr->usage != ACTION_NONE && \
777  envelopeInfoPtr->usage != ACTION_SIGN )
778  return( exitErrorInited( envelopeInfoPtr,
780  return( CRYPT_OK );
781 
783  *checkType = MESSAGE_CHECK_PKC_KA_EXPORT;
784  if( envelopeInfoPtr->usage != ACTION_NONE && \
785  envelopeInfoPtr->usage != ACTION_CRYPT )
786  return( exitErrorInited( envelopeInfoPtr,
788  *usage = ACTION_CRYPT;
789  if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
790  return( exitErrorInited( envelopeInfoPtr,
792  return( CRYPT_OK );
793 
795  *checkType = MESSAGE_CHECK_PKC_ENCRYPT_AVAIL;
796  if( envelopeInfoPtr->iEncryptionKeyset != CRYPT_ERROR )
797  return( exitErrorInited( envelopeInfoPtr,
799  return( CRYPT_OK );
800 
802  *checkType = MESSAGE_CHECK_PKC_DECRYPT_AVAIL;
803  if( envelopeInfoPtr->iDecryptionKeyset != CRYPT_ERROR )
804  return( exitErrorInited( envelopeInfoPtr,
806  return( CRYPT_OK );
807 
810  if( envelopeInfoPtr->iSigCheckKeyset != CRYPT_ERROR )
811  return( exitErrorInited( envelopeInfoPtr,
813  return( CRYPT_OK );
814  }
815 
816  retIntError();
817  }
818 
819 /****************************************************************************
820 * *
821 * Get Attributes *
822 * *
823 ****************************************************************************/
824 
825 /* Get a numeric/boolean attribute */
826 
827 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
828 int getEnvelopeAttribute( INOUT ENVELOPE_INFO *envelopeInfoPtr,
829  OUT_INT_Z int *valuePtr,
830  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
831  {
832  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
833  assert( isWritePtr( valuePtr, sizeof( int ) ) );
834 
835  REQUIRES( isAttribute( attribute ) || \
836  isInternalAttribute( attribute ) );
837 
838  /* Clear return value */
839  *valuePtr = 0;
840 
841  /* Generic attributes are valid for all envelope types */
842  if( attribute == CRYPT_ATTRIBUTE_BUFFERSIZE )
843  {
844  *valuePtr = envelopeInfoPtr->bufSize;
845  return( CRYPT_OK );
846  }
847  if( attribute == CRYPT_ATTRIBUTE_ERRORTYPE )
848  {
849  *valuePtr = envelopeInfoPtr->errorType;
850  return( CRYPT_OK );
851  }
852  if( attribute == CRYPT_ATTRIBUTE_ERRORLOCUS )
853  {
854  *valuePtr = envelopeInfoPtr->errorLocus;
855  return( CRYPT_OK );
856  }
857 
858  /* If we're de-enveloping PGP data, make sure that the attribute is valid
859  for PGP envelopes. We can't perform this check via the ACLs because
860  the data type isn't known at envelope creation time so there's a
861  single generic de-envelope type for which the ACLs allow the union of
862  all de-enveloping attribute types. The following check weeds out the
863  ones that don't work for PGP */
864  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
865  attribute == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
866  return( CRYPT_ARGERROR_VALUE );
867 
868  /* Make sure that the attribute is valid for this envelope type and state */
869  switch( attribute )
870  {
874  /* Algorithm types are valid only for enveloping */
875  if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
876  return( CRYPT_ARGERROR_OBJECT );
877  break;
878 
885  /* The following checks aren't strictly necessary since we can
886  get some information as soon as it's available, but it leads
887  to less confusion (for example without this check we can get
888  signer info long before we can get the signature results,
889  which could be misinterpreted to mean that the signature is
890  bad) and forces the caller to do things cleanly */
891  if( envelopeInfoPtr->usage == ACTION_SIGN && \
892  envelopeInfoPtr->state != STATE_FINISHED )
893  return( CRYPT_ERROR_INCOMPLETE );
894  if( ( envelopeInfoPtr->usage == ACTION_MAC || \
895  ( envelopeInfoPtr->usage == ACTION_CRYPT && \
896  ( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) ) ) && \
897  attribute == CRYPT_ENVINFO_SIGNATURE_RESULT )
898  {
899  if( envelopeInfoPtr->state != STATE_FINISHED )
900  return( CRYPT_ERROR_INCOMPLETE );
901 
902  /* If it's a MACd envelope (either by being directly MACed
903  or as as side-effect of using authenticated encryption)
904  then the signature result isn't held in a content list as
905  for the other signatures since the "signature" is just a
906  MAC tag appended to the data, so there's no need to check
907  for the presence of a content list */
908  break;
909  }
910 
911  /* We're querying something that resides in the content list,
912  make sure that there's a content list present. If it's
913  present but nothing is selected, select the first entry */
914  if( envelopeInfoPtr->contentListCurrent == NULL )
915  {
916  if( envelopeInfoPtr->contentList == NULL )
917  return( exitErrorNotFound( envelopeInfoPtr,
918  attribute ) );
919  envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
920  resetVirtualCursor( envelopeInfoPtr->contentListCurrent );
921  }
922  break;
923 
924  default:
925  REQUIRES( attribute == CRYPT_ENVINFO_COMPRESSION || \
926  attribute == CRYPT_ENVINFO_CONTENTTYPE || \
927  attribute == CRYPT_ENVINFO_INTEGRITY || \
928  attribute == CRYPT_ENVINFO_DETACHEDSIGNATURE || \
929  attribute == CRYPT_IATTRIBUTE_ATTRONLY );
930  }
931 
932  /* Handle the various information types */
933  switch( attribute )
934  {
937  return( getCurrentAttributeInfo( envelopeInfoPtr, valuePtr ) );
938 
940  if( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_NONE )
941  return( exitErrorNotInited( envelopeInfoPtr,
943  *valuePtr = envelopeInfoPtr->defaultAlgo;
944  return( CRYPT_OK );
945 
947  if( envelopeInfoPtr->defaultHash == CRYPT_ALGO_NONE )
948  return( exitErrorNotInited( envelopeInfoPtr,
950  *valuePtr = envelopeInfoPtr->defaultHash;
951  return( CRYPT_OK );
952 
954  if( envelopeInfoPtr->defaultMAC == CRYPT_ALGO_NONE )
955  return( exitErrorNotInited( envelopeInfoPtr,
957  *valuePtr = envelopeInfoPtr->defaultMAC;
958  return( CRYPT_OK );
959 
961  if( envelopeInfoPtr->usage == ACTION_NONE )
962  return( exitErrorNotInited( envelopeInfoPtr,
964  *valuePtr = ( envelopeInfoPtr->usage == ACTION_COMPRESS ) ? \
965  TRUE : FALSE;
966  return( CRYPT_OK );
967 
969  if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
970  return( exitErrorNotFound( envelopeInfoPtr,
972  *valuePtr = envelopeInfoPtr->contentType;
973  return( CRYPT_OK );
974 
976  /* If this isn't signed data or we haven't sorted out the
977  content details yet we don't know whether it's a detached
978  signature or not. We have to make an exception for PGP
979  signed data because the PGP format doesn't record whether a
980  signature is a detached signature or not. To resolve this,
981  the lower-level de-enveloping code takes a guess based on
982  whether the user has manually added a hash for signed-data
983  processing or not. Because of this the detached-signature
984  status can change from (apparently-)false before adding the
985  hash to (apparently-)true after adding it, but there's not
986  much that we can do about this */
987  if( envelopeInfoPtr->usage != ACTION_SIGN || \
988  ( envelopeInfoPtr->type != CRYPT_FORMAT_PGP && \
989  envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE ) )
990  return( exitErrorNotFound( envelopeInfoPtr,
992  *valuePtr = ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) ? \
993  TRUE : FALSE;
994  return( CRYPT_OK );
995 
997  return( getSignatureResult( envelopeInfoPtr, valuePtr ) );
998 
1000  *valuePtr = ( envelopeInfoPtr->usage == ACTION_MAC ) ? \
1002  ( envelopeInfoPtr->usage == ACTION_CRYPT && \
1003  ( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) ) ? \
1005  return( CRYPT_OK );
1006 
1008  return( getSignatureKey( envelopeInfoPtr, valuePtr ) );
1009 
1012  {
1014  CONTENT_LIST *contentListItem = \
1015  envelopeInfoPtr->contentListCurrent;
1016 
1017  REQUIRES( contentListItem != NULL );
1018 
1019  /* Make sure that there's extra data present */
1020  iCryptHandle = \
1021  ( attribute == CRYPT_ENVINFO_SIGNATURE_EXTRADATA ) ? \
1022  contentListItem->clSigInfo.iExtraData : \
1023  contentListItem->clSigInfo.iTimestamp;
1024  if( iCryptHandle == CRYPT_ERROR )
1025  return( exitErrorNotFound( envelopeInfoPtr, attribute ) );
1026 
1027  /* Return it to the caller */
1028  krnlSendNotifier( iCryptHandle, IMESSAGE_INCREFCOUNT );
1029  *valuePtr = iCryptHandle;
1030 
1031  return( CRYPT_OK );
1032  }
1033 
1034  case CRYPT_IATTRIBUTE_ATTRONLY:
1035  /* If this isn't signed data we don't know whether it's an
1036  attributes-only message or not */
1037  if( envelopeInfoPtr->usage != ACTION_SIGN )
1038  return( exitErrorNotFound( envelopeInfoPtr,
1039  CRYPT_IATTRIBUTE_ATTRONLY ) );
1040 
1041  *valuePtr = ( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY ) ? \
1042  TRUE : FALSE;
1043  return( CRYPT_OK );
1044  }
1045 
1046  retIntError();
1047  }
1048 
1049 /* Get a string attribute */
1050 
1051 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1052 int getEnvelopeAttributeS( INOUT ENVELOPE_INFO *envelopeInfoPtr,
1054  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
1055  {
1057  int status;
1058 
1059  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1060  assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
1061 
1062  REQUIRES( isAttribute( attribute ) || \
1063  isInternalAttribute( attribute ) );
1064 
1065  /* If we're querying something that resides in the content list make
1066  sure that there's a content list present. If it's present but
1067  nothing is selected, select the first entry */
1068  if( attribute == CRYPT_ENVINFO_PRIVATEKEY_LABEL && \
1069  envelopeInfoPtr->contentListCurrent == NULL )
1070  {
1071  if( envelopeInfoPtr->contentList == NULL )
1072  return( exitErrorNotFound( envelopeInfoPtr,
1074  envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
1075  resetVirtualCursor( envelopeInfoPtr->contentListCurrent );
1076  }
1077 
1078  /* Generic attributes are valid for all envelope types */
1079  if( attribute == CRYPT_ATTRIBUTE_ERRORMESSAGE )
1080  {
1081 #ifdef USE_ERRMSGS
1082  ERROR_INFO *errorInfo = &envelopeInfoPtr->errorInfo;
1083 
1084  if( errorInfo->errorStringLength > 0 )
1085  {
1086  return( attributeCopy( msgData, errorInfo->errorString,
1087  errorInfo->errorStringLength ) );
1088  }
1089 #endif /* USE_ERRMSGS */
1090 
1091  /* We don't set extended error information for this atribute because
1092  it's usually read in response to an existing error, which would
1093  overwrite the existing error information */
1094  return( CRYPT_ERROR_NOTFOUND );
1095  }
1096  if( attribute == CRYPT_ENVINFO_PRIVATEKEY_LABEL )
1097  {
1098  MESSAGE_KEYMGMT_INFO getkeyInfo;
1099  char label[ CRYPT_MAX_TEXTSIZE + 8 ];
1100 
1101  /* Make sure that the current required resource is a private key and
1102  that there's a keyset available to pull the key from */
1103  contentListItem = envelopeInfoPtr->contentListCurrent;
1104  if( contentListItem->envInfo != CRYPT_ENVINFO_PRIVATEKEY )
1105  return( exitErrorNotFound( envelopeInfoPtr,
1107  if( envelopeInfoPtr->iDecryptionKeyset == CRYPT_ERROR )
1108  return( exitErrorNotInited( envelopeInfoPtr,
1110 
1111  /* Try and get the key label information. Since we're accessing the
1112  key by (unique) key ID there's no real need to specify a
1113  preference for encryption keys */
1114  if( contentListItem->issuerAndSerialNumber == NULL )
1115  {
1116  setMessageKeymgmtInfo( &getkeyInfo,
1117  ( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
1118  CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
1119  contentListItem->keyID,
1120  contentListItem->keyIDsize,
1121  label, CRYPT_MAX_TEXTSIZE,
1123  }
1124  else
1125  {
1126  setMessageKeymgmtInfo( &getkeyInfo,
1127  CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
1128  contentListItem->issuerAndSerialNumber,
1129  contentListItem->issuerAndSerialNumberSize,
1130  label, CRYPT_MAX_TEXTSIZE,
1132  }
1133  status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
1134  IMESSAGE_KEY_GETKEY, &getkeyInfo,
1136  if( cryptStatusError( status ) )
1137  {
1138  retExtObj( status,
1139  ( status, ENVELOPE_ERRINFO,
1140  envelopeInfoPtr->iDecryptionKeyset,
1141  "Couldn't retrieve private-key label from "
1142  "keyset/device" ) );
1143  }
1144  return( attributeCopy( msgData, getkeyInfo.auxInfo,
1145  getkeyInfo.auxInfoLength ) );
1146  }
1147 
1148  retIntError();
1149  }
1150 
1151 /****************************************************************************
1152 * *
1153 * Set Attributes *
1154 * *
1155 ****************************************************************************/
1156 
1157 /* Set a numeric/boolean attribute */
1158 
1159 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1160 int setEnvelopeAttribute( INOUT ENVELOPE_INFO *envelopeInfoPtr,
1161  IN_INT_Z const int value,
1162  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
1163  {
1165  ACTION_TYPE usage = ACTION_NONE;
1166  typedef struct {
1167  const CRYPT_ATTRIBUTE_TYPE type; /* Attribute type */
1168  const ACTION_TYPE usage; /* Corresponding usage type */
1169  const MESSAGE_CHECK_TYPE checkType; /* and check type */
1170  } CHECK_INFO;
1171  static const CHECK_INFO checkTable[] = {
1172  /* The following checks are fairly stereotyped and can be selected
1173  via a lookup table. Envelope attributes that require more
1174  specialised checking are handled via custom code in a case
1175  statement */
1176 #ifdef USE_COMPRESSION
1178 #endif /* USE_COMPRESSION */
1186  { CRYPT_IATTRIBUTE_INCLUDESIGCERT, ACTION_SIGN, MESSAGE_CHECK_NONE },
1187  { CRYPT_IATTRIBUTE_ATTRONLY, ACTION_SIGN, MESSAGE_CHECK_NONE },
1189  };
1190  int i, status;
1191 
1192  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1193 
1194  REQUIRES( ( attribute == CRYPT_ENVINFO_COMPRESSION || \
1195  attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
1196  attribute == CRYPT_ATTRIBUTE_CURRENT ) ||
1197  /* Compression = CRYPT_UNUSED, CURRENT = cursor positioning
1198  code */
1199  ( value >= 0 && value < MAX_INTLENGTH ) );
1200  REQUIRES( isAttribute( attribute ) || \
1201  isInternalAttribute( attribute ) );
1202 
1203  /* Generic attributes are valid for all envelope types */
1204  if( attribute == CRYPT_ATTRIBUTE_BUFFERSIZE )
1205  {
1206  envelopeInfoPtr->bufSize = value;
1207  return( CRYPT_OK );
1208  }
1209 
1210  /* If it's meta-information, process it now */
1211  if( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
1212  attribute == CRYPT_ATTRIBUTE_CURRENT )
1213  {
1214  const CONTENT_LIST *contentListCursor;
1215 
1216  /* If it's an absolute positioning code, pre-set the attribute
1217  cursor if required */
1218  if( value == CRYPT_CURSOR_FIRST || value == CRYPT_CURSOR_LAST )
1219  {
1220  if( envelopeInfoPtr->contentList == NULL )
1221  return( CRYPT_ERROR_NOTFOUND );
1222 
1223  ENSURES( envelopeInfoPtr->contentList != NULL );
1224 
1225  /* If it's an absolute attribute positioning code, reset the
1226  attribute cursor to the start of the list before we try to
1227  move it and if it's an attribute positioning code initialise
1228  the attribute cursor if necessary */
1229  if( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
1230  envelopeInfoPtr->contentListCurrent == NULL )
1231  {
1232  envelopeInfoPtr->contentListCurrent = \
1233  envelopeInfoPtr->contentList;
1234  if( envelopeInfoPtr->contentListCurrent != NULL )
1235  resetVirtualCursor( envelopeInfoPtr->contentListCurrent );
1236  }
1237 
1238  /* If there are no attributes present, return the appropriate
1239  error code */
1240  if( envelopeInfoPtr->contentListCurrent == NULL )
1241  {
1242  return( ( value == CRYPT_CURSOR_FIRST || \
1243  value == CRYPT_CURSOR_LAST ) ? \
1246  }
1247  }
1248  else
1249  {
1250  /* It's a relative positioning code, return a not-inited error
1251  rather than a not-found error if the cursor isn't set since
1252  there may be attributes present but the cursor hasn't been
1253  initialised yet by selecting the first or last absolute
1254  attribute */
1255  if( envelopeInfoPtr->contentListCurrent == NULL )
1256  return( CRYPT_ERROR_NOTINITED );
1257  }
1258  ENSURES( envelopeInfoPtr->contentListCurrent != NULL );
1259 
1260  /* Move the cursor */
1261  contentListCursor = ( const CONTENT_LIST * ) \
1262  attributeMoveCursor( envelopeInfoPtr->contentListCurrent,
1263  getAttrFunction, attribute, value );
1264  if( contentListCursor == NULL )
1265  return( CRYPT_ERROR_NOTFOUND );
1266  envelopeInfoPtr->contentListCurrent = \
1267  ( CONTENT_LIST * ) contentListCursor;
1268  return( CRYPT_OK );
1269  }
1270 
1271  /* In general we can't add new enveloping information once we've started
1272  processing data */
1273  if( envelopeInfoPtr->state != STATE_PREDATA )
1274  {
1275  /* We can't add new information once we've started enveloping */
1276  if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
1277  return( CRYPT_ERROR_INITED );
1278 
1279  /* We can only add signature check information once we've started
1280  de-enveloping */
1281  if( attribute != CRYPT_ENVINFO_SIGNATURE )
1282  return( CRYPT_ERROR_INITED );
1283  }
1284 
1285  /* If we're de-enveloping PGP data, make sure that the attribute is
1286  valid for PGP envelopes. We can't perform this check via the ACLs
1287  because the data type isn't known at envelope creation time so
1288  there's a single generic de-envelope type for which the ACLs allow
1289  the union of all de-enveloping attribute types. The following check
1290  weeds out the ones that don't work for PGP */
1291  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
1292  {
1293  if( attribute == CRYPT_OPTION_ENCR_MAC || \
1294  attribute == CRYPT_ENVINFO_INTEGRITY || \
1295  attribute == CRYPT_ENVINFO_KEY || \
1296  attribute == CRYPT_ENVINFO_SESSIONKEY )
1297  return( CRYPT_ARGERROR_VALUE );
1298  if( attribute == CRYPT_ENVINFO_HASH && \
1299  !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
1300  {
1301  /* We can add a hash if we're creating a detached signature */
1302  return( CRYPT_ARGERROR_VALUE );
1303  }
1304  }
1305 
1306  /* Since the information may not be used for quite some time after it's
1307  added we do some preliminary checking here to allow us to return an
1308  error code immediately rather than from some deeply-buried function an
1309  indeterminate time in the future. Since much of the checking is
1310  similar, we use a table-driven check for most types and fall back to
1311  custom checking for special cases */
1312  for( i = 0; checkTable[ i ].type != ACTION_NONE && \
1313  i < FAILSAFE_ARRAYSIZE( checkTable, CHECK_INFO ); i++ )
1314  {
1315  if( checkTable[ i ].type == attribute )
1316  {
1317  if( envelopeInfoPtr->usage != ACTION_NONE && \
1318  envelopeInfoPtr->usage != checkTable[ i ].usage )
1319  return( exitErrorInited( envelopeInfoPtr, attribute ) );
1320  usage = checkTable[ i ].usage;
1321  checkType = checkTable[ i ].checkType;
1322  break;
1323  }
1324  }
1325  ENSURES( i < FAILSAFE_ARRAYSIZE( checkTable, CHECK_INFO ) );
1326  if( usage != ACTION_NONE )
1327  {
1328  /* Make sure that the usage requirements for the item that we're
1329  about to add are consistent */
1330  if( envelopeInfoPtr->usage != ACTION_NONE && \
1331  envelopeInfoPtr->usage != usage )
1332  return( exitErrorInited( envelopeInfoPtr,
1333  attribute ) );
1334  }
1335  else
1336  {
1337  /* It's not a general class of action, perform special-case usage
1338  checking */
1339  status = checkOtherAttribute( envelopeInfoPtr, value, attribute,
1340  &usage, &checkType );
1341  if( cryptStatusError( status ) )
1342  {
1343  /* An attribute that's handled internally will return OK_SPECIAL
1344  to indicate that there's nothing further to do */
1345  if( status == OK_SPECIAL )
1346  return( CRYPT_OK );
1347 
1348  return( status );
1349  }
1350  }
1351 
1352  if( checkType != MESSAGE_CHECK_NONE )
1353  {
1354  /* Check the object as appropriate */
1355  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL, checkType );
1356  if( cryptStatusError( status ) )
1357  return( CRYPT_ARGERROR_NUM1 );
1358 
1359  /* Make sure that the object corresponds to a representable algorithm
1360  type. Note that this check isn't totally foolproof on de-
1361  enveloping PGP data since the user can push in the hash context
1362  before they push in the signed data (to signifiy the use of a
1363  detached signature) so it'd be checked using the default (CMS)
1364  algorithm values rather than the PGP ones */
1365  if( checkType == MESSAGE_CHECK_PKC_ENCRYPT || \
1366  checkType == MESSAGE_CHECK_PKC_DECRYPT || \
1367  checkType == MESSAGE_CHECK_PKC_SIGN || \
1368  checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
1369  checkType == MESSAGE_CHECK_CRYPT || \
1370  checkType == MESSAGE_CHECK_HASH || \
1371  checkType == MESSAGE_CHECK_MAC )
1372  {
1374 
1375  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
1376  &algorithm, CRYPT_CTXINFO_ALGO );
1377  if( cryptStatusOK( status ) && checkType == MESSAGE_CHECK_CRYPT )
1378  {
1379  /* It's a conventional-encryption context, get the mode as
1380  well */
1381  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
1382  &mode, CRYPT_CTXINFO_MODE );
1383  }
1384  if( cryptStatusError( status ) )
1385  return( CRYPT_ARGERROR_NUM1 );
1386  if( !envelopeInfoPtr->checkAlgo( algorithm, mode ) )
1387  return( CRYPT_ERROR_NOTAVAIL );
1388  }
1389 
1390  /* If we're using CMS enveloping then the object must have an
1391  initialised certificate of the correct type associated with it.
1392  Most of this will be caught by the kernel but there are a couple
1393  of special cases (e.g. an attribute certificate where the main
1394  object is a PKC context) which are missed by the general kernel
1395  checks */
1396  if( ( attribute == CRYPT_ENVINFO_SIGNATURE || \
1397  attribute == CRYPT_ENVINFO_PUBLICKEY || \
1398  attribute == CRYPT_ENVINFO_PRIVATEKEY || \
1399  attribute == CRYPT_ENVINFO_ORIGINATOR ) &&
1400  ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
1401  envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
1402  {
1403  int inited, certType;
1404 
1405  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
1406  &certType, CRYPT_CERTINFO_CERTTYPE );
1407  if( cryptStatusError( status ) ||
1408  ( certType != CRYPT_CERTTYPE_CERTIFICATE && \
1409  certType != CRYPT_CERTTYPE_CERTCHAIN ) )
1410  {
1411  /* These objects work with CRYPT_FORMAT_CRYPTLIB but not
1412  CRYPT_FORMAT_CMS/SMIME, which may be confusing for some
1413  users so we try and provide somewhat more detailed
1414  information on what the problem is. Since it's the
1415  result of a complex dependency it's a bit difficult to
1416  do, the following is about the best that we can manage */
1417  setErrorInfo( envelopeInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1419  return( CRYPT_ARGERROR_NUM1 );
1420  }
1421  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &inited,
1423  if( cryptStatusError( status ) || !inited )
1424  return( CRYPT_ARGERROR_NUM1 );
1425  }
1426  }
1427 
1428  /* Add it to the envelope */
1429  status = envelopeInfoPtr->addInfo( envelopeInfoPtr, attribute,
1430  value );
1431  if( cryptStatusError( status ) )
1432  {
1433  if( status == CRYPT_ERROR_INITED )
1434  return( exitErrorInited( envelopeInfoPtr, attribute ) );
1435  return( status );
1436  }
1437  if( usage != ACTION_NONE )
1438  {
1439  /* The action was successfully added, update the usage if
1440  necessary */
1441  envelopeInfoPtr->usage = usage;
1442 
1443  /* If we're encrypting the content and using the cryptlib native
1444  format, enabled authenticated encryption by default unless we're
1445  using raw session-key based encryption, which precludes using
1446  authenticated encryption. Unfortunately we can't do this for
1447  CMS / S/MIME because of backwards-compatibility considerations
1448  with other implementations */
1449  if( usage == ACTION_CRYPT && \
1450  envelopeInfoPtr->type == CRYPT_FORMAT_CRYPTLIB && \
1451  attribute != CRYPT_ENVINFO_SESSIONKEY )
1452  envelopeInfoPtr->flags |= ENVELOPE_AUTHENC;
1453  }
1454  return( CRYPT_OK );
1455  }
1456 
1457 /* Set a string attribute */
1458 
1459 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1460 int setEnvelopeAttributeS( INOUT ENVELOPE_INFO *envelopeInfoPtr,
1461  IN_BUFFER( dataLength ) const void *data,
1462  IN_LENGTH const int dataLength,
1463  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
1464  {
1465  ACTION_TYPE usage = ACTION_NONE;
1466  int status;
1467 
1468  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1469  assert( isReadPtr( data, dataLength ) );
1470 
1471  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
1472  REQUIRES( isAttribute( attribute ) || \
1473  isInternalAttribute( attribute ) );
1474 
1475  /* Handle the various information types */
1476  switch( attribute )
1477  {
1479  /* Set the envelope usage type based on the fact that we've been
1480  fed a password */
1481  if( envelopeInfoPtr->usage == ACTION_NONE )
1482  usage = ACTION_CRYPT;
1483  else
1484  {
1485  if( envelopeInfoPtr->usage != ACTION_CRYPT && \
1486  envelopeInfoPtr->usage != ACTION_MAC )
1487  return( exitErrorInited( envelopeInfoPtr,
1489  }
1490 
1491  /* In general we can't add new enveloping information once we've
1492  started processing data */
1493  if( envelopeInfoPtr->state != STATE_PREDATA && \
1494  !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
1495  {
1496  /* We can't add new information once we've started enveloping */
1497  return( exitErrorInited( envelopeInfoPtr,
1499  }
1500 
1501  /* Add it to the envelope */
1502  status = envelopeInfoPtr->addInfoString( envelopeInfoPtr,
1503  CRYPT_ENVINFO_PASSWORD, data, dataLength );
1504  break;
1505 
1507  {
1508  MESSAGE_KEYMGMT_INFO getkeyInfo;
1509 
1510  /* Set the envelope usage type based on the fact that we've been
1511  fed a recipient email address */
1512  if( envelopeInfoPtr->usage != ACTION_NONE && \
1513  envelopeInfoPtr->usage != ACTION_CRYPT )
1514  return( CRYPT_ARGERROR_VALUE );
1515  usage = ACTION_CRYPT;
1516 
1517  /* Make sure that there's a keyset available to pull the
1518  recipient's key from */
1519  if( envelopeInfoPtr->iEncryptionKeyset == CRYPT_ERROR )
1520  return( exitErrorNotInited( envelopeInfoPtr,
1522 
1523  /* Try and read the recipient's key from the keyset. Some
1524  keysets (particularly PKCS #11 devices, for which apps set
1525  the usage flags more or less at random) may not be able to
1526  differentiate between encryption and signature keys based on
1527  the information that they have. This isn't a problem when
1528  matching a key based on a unique ID but with the use of the
1529  recipient name as the ID there could be multiple possible
1530  matches. Before we try and use the key we therefore perform
1531  an extra check here to make sure that it really is an
1532  encryption-capable key */
1533  setMessageKeymgmtInfo( &getkeyInfo, CRYPT_KEYID_URI, data,
1534  dataLength, NULL, 0,
1536  status = krnlSendMessage( envelopeInfoPtr->iEncryptionKeyset,
1537  IMESSAGE_KEY_GETKEY, &getkeyInfo,
1539  if( status == CRYPT_ERROR_NOTFOUND )
1540  {
1541  /* Technically what we're looking for is an email address
1542  (since this facility is meant for email encryption, thus
1543  the "recipient" in the name) but it's possible that it's
1544  being used in a more general manner to mean "any random
1545  key label", so if the fetch based on email address fails
1546  we try again with a fetch based on name */
1547  setMessageKeymgmtInfo( &getkeyInfo, CRYPT_KEYID_NAME, data,
1548  dataLength, NULL, 0,
1550  status = krnlSendMessage( envelopeInfoPtr->iEncryptionKeyset,
1551  IMESSAGE_KEY_GETKEY, &getkeyInfo,
1553  }
1554  if( cryptStatusError( status ) )
1555  {
1556  retExtObj( status,
1557  ( status, ENVELOPE_ERRINFO,
1558  envelopeInfoPtr->iEncryptionKeyset,
1559  "Couldn't retrieve encryption key from keyset" ) );
1560  }
1561  if( cryptStatusError( \
1563  NULL, MESSAGE_CHECK_PKC_ENCRYPT ) ) )
1564  {
1565  krnlSendNotifier( getkeyInfo.cryptHandle,
1567  return( CRYPT_ERROR_NOTFOUND );
1568  }
1569  if( cryptStatusOK( status ) )
1570  {
1571  /* We got the key, add it to the envelope */
1572  status = envelopeInfoPtr->addInfo( envelopeInfoPtr,
1574  getkeyInfo.cryptHandle );
1575  krnlSendNotifier( getkeyInfo.cryptHandle,
1577  }
1578  break;
1579  }
1580 
1581  default:
1582  retIntError();
1583  }
1584  if( cryptStatusError( status ) )
1585  {
1586  if( status == CRYPT_ERROR_INITED )
1587  return( exitErrorInited( envelopeInfoPtr, attribute ) );
1588  return( status );
1589  }
1590  if( usage != ACTION_NONE )
1591  {
1592  /* The action was successfully added, update the usage if
1593  necessary */
1594  envelopeInfoPtr->usage = usage;
1595  }
1596  return( CRYPT_OK );
1597  }
1598 
1599 #endif /* USE_ENVELOPES */