2  * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. 
   4  * The contents of this file constitute Original Code as defined in and are 
   5  * subject to the Apple Public Source License Version 1.2 (the 'License'). 
   6  * You may not use this file except in compliance with the License. Please obtain 
   7  * a copy of the License at http://www.apple.com/publicsource and read it before 
  10  * This Original Code and all software distributed under the License are 
  11  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 
  12  * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 
  13  * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
  14  * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 
  15  * specific language governing rights and limitations under the License. 
  20  * FEECSPUtils.h - Misc. utility function for FEE/CryptKit CSP.  
  24 #ifdef  CRYPTKIT_CSP_ENABLE 
  26 #include <security_utilities/debugging.h> 
  27 #include <security_utilities/logging.h> 
  28 #include "FEECSPUtils.h" 
  30 #include <security_cryptkit/feeFunctions.h> 
  31 #include <security_cryptkit/feePublicKey.h> 
  33 #define feeMiscDebug(args...)   secinfo("feeMisc", ## args) 
  35 /* Given a FEE error, throw appropriate CssmError */ 
  36 void CryptKit::throwCryptKit( 
  38         const char      *op
)            /* optional */ 
  41                 Security::Syslog::error("Apple CSP %s: %s", op
, feeReturnString(frtn
)); 
  47                 case FR_BadPubKeyString
: 
  48                 case FR_IncompatibleKey
: 
  50                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
  52                         CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
); 
  53                 case FR_BadSignatureFormat
:             /* signature corrupted */ 
  54                         CssmError::throwMe(CSSMERR_CSP_INVALID_SIGNATURE
); 
  55                 case FR_InvalidSignature
:               /* signature intact, but not valid */ 
  56                         CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED
); 
  57                 case FR_IllegalArg
:                     /* illegal argument */ 
  58                         CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
); 
  59                 case FR_BadCipherText
:          /* malformed ciphertext */ 
  60                 case FR_BadEnc64
:                       /* bad enc64() format */ 
  61                         CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
); 
  62                 case FR_Unimplemented
:          /* unimplemented function */ 
  63                         CssmError::throwMe(CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
); 
  64                 case FR_Memory
:         /* unimplemented function */ 
  65                         CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
); 
  66                 case FR_ShortPrivData
: 
  67                         CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
); 
  68                 case FR_IllegalCurve
:           /* e.g., ECDSA with Montgomery curve */ 
  69                         CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY
); 
  71                 /* I don't think we should ever see these no matter what the  
  72                  * caller throws at us */ 
  73                 case FR_WrongSignatureType
:     /* ElGamal vs. ECDSA */ 
  74                 case FR_BadUsageName
:           /* bad usageName */ 
  75                 case FR_BadCipherFile
: 
  76                 case FR_Internal
:                       /* internal library error */ 
  77                         CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
); 
  83  * -- obtain CSSM key of specified CSSM_ATTRIBUTE_TYPE 
  84  * -- validate keyClass 
  85  * -- validate keyUsage 
  86  * -- convert to feePubKey, allocating the feePubKey if necessary 
  88  * Returned key can be of algorithm CSSM_ALGID_ECDSA or CSSM_ALGID_FEE;  
  89  * caller has to verify proper algorithm for operation. 
  91 feePubKey 
CryptKit::contextToFeeKey( 
  92         const Context           
&context
, 
  93         AppleCSPSession         
&session
, 
  94         CSSM_ATTRIBUTE_TYPE     attrType
,         // CSSM_ATTRIBUTE_KEY, CSSM_ATTRIBUTE_PUBLIC_KEY 
  95         CSSM_KEYCLASS           keyClass
,         // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY 
  96         CSSM_KEYUSE                     usage
,            // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc. 
  97         bool                            &mallocdKey
)  // RETURNED 
 100                 context
.get
<CssmKey
>(attrType
, CSSMERR_CSP_MISSING_ATTR_KEY
); 
 101         const CSSM_KEYHEADER 
&hdr 
= cssmKey
.KeyHeader
; 
 102         switch(hdr
.AlgorithmId
) { 
 104                 case CSSM_ALGID_ECDSA
: 
 107                         CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH
); 
 109         if(hdr
.KeyClass 
!= keyClass
) { 
 110                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
 112         cspValidateIntendedKeyUsage(&hdr
, usage
); 
 113         cspVerifyKeyTimes(hdr
); 
 114         return cssmKeyToFee(cssmKey
, session
, mallocdKey
); 
 118  * Convert a CssmKey to a feePubKey. May result in the creation of a new 
 119  * feePubKey (when cssmKey is a raw key); allocdKey is true in that case 
 120  * in which case the caller generally has to free the allocd key). 
 122 feePubKey 
CryptKit::cssmKeyToFee( 
 123         const CssmKey   
&cssmKey
, 
 124         AppleCSPSession 
&session
, 
 125         bool                    &allocdKey
)     // RETURNED 
 127         feePubKey feeKey 
= NULL
; 
 130         const CSSM_KEYHEADER 
*hdr 
= &cssmKey
.KeyHeader
; 
 131         switch(hdr
->AlgorithmId
) { 
 133                 case CSSM_ALGID_ECDSA
: 
 136                         // someone else's key (should never happen) 
 137                         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 139         switch(hdr
->BlobType
) { 
 140                 case CSSM_KEYBLOB_RAW
: 
 141                         feeKey 
= rawCssmKeyToFee(cssmKey
); 
 144                 case CSSM_KEYBLOB_REFERENCE
: 
 146                         BinaryKey 
&binKey 
= session
.lookupRefKey(cssmKey
); 
 147                         FEEBinaryKey 
*feeBinKey 
= dynamic_cast<FEEBinaryKey 
*>(&binKey
); 
 148                         /* this cast failing means that this is some other 
 149                          * kind of binary key */ 
 150                         if(feeBinKey 
== NULL
) { 
 151                                 feeMiscDebug("CryptKit::cssmKeyToFee: wrong BinaryKey subclass\n"); 
 152                                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 154                         assert(feeBinKey
->feeKey() != NULL
); 
 155                         feeKey 
= feeBinKey
->feeKey(); 
 159                         CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT
); 
 165  * Convert a raw CssmKey to a newly alloc'd feePubKey. 
 167 feePubKey 
CryptKit::rawCssmKeyToFee( 
 168         const CssmKey   
&cssmKey
) 
 170         const CSSM_KEYHEADER 
*hdr 
= &cssmKey
.KeyHeader
; 
 171         assert(hdr
->BlobType 
== CSSM_KEYBLOB_RAW
);  
 173         switch(hdr
->AlgorithmId
) { 
 175                 case CSSM_ALGID_ECDSA
: 
 178                         // someone else's key (should never happen) 
 179                         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 182         switch(hdr
->KeyClass
) { 
 183                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 184                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
 187                         // someone else's key 
 188                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
 191         feePubKey feeKey 
= feePubKeyAlloc(); 
 193                 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
); 
 196         feeReturn frtn 
= FR_IllegalArg
; 
 197         bool badFormat 
= false; 
 200          * The actual key init depends on key type and incoming format 
 202         switch(hdr
->AlgorithmId
) { 
 204                         switch(hdr
->KeyClass
) { 
 205                                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 206                                         switch(hdr
->Format
) { 
 207                                                 case FEE_KEYBLOB_DEFAULT_FORMAT
: 
 208                                                         /* FEE, public key, default: custom DER */ 
 209                                                         frtn 
= feePubKeyInitFromDERPubBlob(feeKey
, 
 210                                                                 cssmKey
.KeyData
.Data
, 
 211                                                                 cssmKey
.KeyData
.Length
); 
 213                                                 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
: 
 214                                                         /* FEE, public key, native byte stream */ 
 215                                                         frtn 
= feePubKeyInitFromPubBlob(feeKey
, 
 216                                                                 cssmKey
.KeyData
.Data
, 
 217                                                                 (unsigned int)cssmKey
.KeyData
.Length
); 
 224                                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
 225                                         switch(hdr
->Format
) { 
 226                                                 case FEE_KEYBLOB_DEFAULT_FORMAT
: 
 227                                                         /* FEE, private key, default: custom DER */ 
 228                                                         frtn 
= feePubKeyInitFromDERPrivBlob(feeKey
, 
 229                                                                 cssmKey
.KeyData
.Data
, 
 230                                                                 cssmKey
.KeyData
.Length
); 
 232                                                 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
: 
 233                                                         /* FEE, private key, native byte stream */ 
 234                                                         frtn 
= feePubKeyInitFromPrivBlob(feeKey
, 
 235                                                                 cssmKey
.KeyData
.Data
, 
 236                                                                 (unsigned int)cssmKey
.KeyData
.Length
); 
 244                                         /* not reached, we already checked */ 
 247                         /* end of case ALGID_FEE */ 
 250                 case CSSM_ALGID_ECDSA
: 
 251                         switch(hdr
->KeyClass
) { 
 252                                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 253                                         switch(hdr
->Format
) { 
 254                                                 case CSSM_KEYBLOB_RAW_FORMAT_NONE
: 
 255                                                 case CSSM_KEYBLOB_RAW_FORMAT_X509
: 
 256                                                         /* ECDSA, public key, default: X509 */ 
 257                                                         frtn 
= feePubKeyInitFromX509Blob(feeKey
, 
 258                                                                 cssmKey
.KeyData
.Data
, 
 259                                                                 cssmKey
.KeyData
.Length
); 
 262                                                 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
: 
 264                                                          * An oddity here: we can parse this incoming key, but  
 265                                                          * it contains both private and public parts. We throw 
 266                                                          * out the private component here. 
 268                                                         frtn 
= feePubKeyInitFromOpenSSLBlob(feeKey
,  
 270                                                                 cssmKey
.KeyData
.Data
, 
 271                                                                 cssmKey
.KeyData
.Length
); 
 274                                                  * NOTE: we cannot *import* a key in raw X9.62 format. 
 275                                                  * We'd need to know the curve, i.e., the feeDepth. 
 276                                                  * I suppose we could infer that from the blob length but 
 277                                                  * a better way would be to have a new context attribute 
 278                                                  * specifying which curve. 
 279                                                  * For now, imported raw keys have to be in X509 format. 
 281                                                 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
: 
 287                                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
 288                                         switch(hdr
->Format
) { 
 289                                                 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8
: 
 290                                                         /* ECDSA, private key, PKCS8 */ 
 291                                                         frtn 
= feePubKeyInitFromPKCS8Blob(feeKey
, 
 292                                                                 cssmKey
.KeyData
.Data
, 
 293                                                                 cssmKey
.KeyData
.Length
); 
 296                                                 case CSSM_KEYBLOB_RAW_FORMAT_NONE
: 
 297                                                 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
: 
 298                                                         /* ECDSA, private, default: OpenSSL */ 
 299                                                         /* see comment above re: OpenSSL public/private keys */ 
 300                                                         frtn 
= feePubKeyInitFromOpenSSLBlob(feeKey
,  
 302                                                                 cssmKey
.KeyData
.Data
, 
 303                                                                 cssmKey
.KeyData
.Length
); 
 305                                                 /* see comment above about X9.62 format public key blobs */ 
 306                                                 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
: 
 313                                         /* not reached, we already checked */ 
 316                         /* end of case CSSM_ALGID_ECDSA */ 
 320                 CssmError::throwMe(hdr
->KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
? 
 321                         CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT 
: 
 322                         CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT
); 
 325                 feePubKeyFree(feeKey
); 
 326                 throwCryptKit(frtn
, "feePubKeyInitFromKeyBlob"); 
 332  * Glue function which allows C code to use AppleCSPSession  
 333  * as an RNG. A ptr to this function gets passed down to  
 334  * CryptKit C functions as a feeRandFcn. 
 336 feeReturn 
CryptKit::feeRandCallback( 
 337         void *ref
,                                      // actually an AppleCSPSession * 
 338         unsigned char *bytes
,           // must be alloc'd by caller  
 341         AppleCSPSession 
*session 
=  
 342                 reinterpret_cast<AppleCSPSession 
*>(ref
); 
 344                 session
->getRandomBytes(numBytes
, bytes
); 
 352 #endif  /* CRYPTKIT_CSP_ENABLE */