]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_apple_csp/lib/pkcs8.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_csp / lib / pkcs8.cpp
diff --git a/libsecurity_apple_csp/lib/pkcs8.cpp b/libsecurity_apple_csp/lib/pkcs8.cpp
new file mode 100644 (file)
index 0000000..d0dc5b8
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please obtain
+ * a copy of the License at http://www.apple.com/publicsource and read it before
+ * using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+ * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+ * specific language governing rights and limitations under the License.
+ */
+
+
+//
+// pkcs8.cpp - PKCS8 key wrap/unwrap support.
+//
+
+
+#include "pkcs8.h"
+#include "AppleCSPUtils.h"
+#include "AppleCSPKeys.h"
+#include <Security/keyTemplates.h>
+#include <security_asn1/SecNssCoder.h>
+#include <security_asn1/nssUtils.h>
+#include "AppleCSPSession.h"
+#include <Security/cssmapple.h>
+
+/*
+ * Given a key in PKCS8 format, fill in the following
+ * header fields:
+ *
+ *     CSSM_KEYBLOB_FORMAT Format
+ *  CSSM_ALGORITHMS AlgorithmId
+ *  uint32 LogicalKeySizeInBits
+ */
+void AppleCSPSession::pkcs8InferKeyHeader( 
+       CssmKey                 &key)
+{
+       /* 
+        * Incoming key blob is a PrivateKeyInfo. Take it apart
+        * to get its algorithm info, from which we infer other
+        * fields.
+        */
+       NSS_PrivateKeyInfo privKeyInfo;
+       SecNssCoder coder;
+       CSSM_DATA &keyData = key.KeyData;
+       
+       memset(&privKeyInfo, 0, sizeof(privKeyInfo));
+       if(coder.decodeItem(keyData, kSecAsn1PrivateKeyInfoTemplate,
+                       &privKeyInfo)) {
+               errorLog0("pkcs8InferKeyHeader decode error\n");
+               CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+       }
+       
+       CSSM_KEYHEADER &hdr = key.KeyHeader;
+       if(!cssmOidToAlg(&privKeyInfo.algorithm.algorithm, 
+                       &hdr.AlgorithmId)) {
+               errorLog0("pkcs8InferKeyHeader unknown algorithm\n");
+               CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
+       }
+       
+       switch(hdr.AlgorithmId) {
+               case CSSM_ALGID_RSA:
+               case CSSM_ALGID_ECDSA:
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; 
+                       break;
+               case CSSM_ALGID_DSA:
+                       /* 
+                        * Try openssl style first, though our default when 
+                        * wrapping is FIPS186
+                        */
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+                       break;
+               default:
+                       /* punt */
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
+                       break;
+       }
+       
+       /* 
+        * Find someone who knows about this key and ask them the
+        * key size. infoProvider() throws if no provider found.
+        */
+       CSSM_KEY_SIZE keySize;
+       try {
+               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+               provider->QueryKeySizeInBits(keySize);
+       }
+       catch(const CssmError &cerror) {
+               /*
+                * Special case: DSA private keys keys can be in two forms - FIPS186
+                * (for legacy implementations) and PKCS8 (for openssl). We're wired to
+                * *generate* FIPS186 blobs by default in pkcs8RawKeyFormat(), but to 
+                * decode openssl-generated DSA private keys in wrapped FIPS186 format
+                * we have to try both. 
+                */
+               if((cerror.error == CSSMERR_CSP_INVALID_KEY) &&
+                  (hdr.AlgorithmId == CSSM_ALGID_DSA)) {
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
+                       try {
+                               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+                               provider->QueryKeySizeInBits(keySize);
+                       }
+                       catch(...) {
+                               /* out of luck */
+                               throw;
+                       }
+               }
+               else {
+                       /* other error, give up */
+                       throw;
+               }
+       }
+       catch(...) {
+               /* other (non-CSSM) error, give up */
+               throw;
+       }
+       hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
+}
+
+/*
+ * When doing a PKCS8 wrap operation on a reference key, this
+ * is used to infer the blob type to obtain before the encryption.
+ * App can override this with a 
+ * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT 
+ * context attribute. 
+ */
+CSSM_KEYBLOB_FORMAT pkcs8RawKeyFormat(
+       CSSM_ALGORITHMS keyAlg)
+{
+       switch(keyAlg) {
+               case CSSM_ALGID_RSA:
+               case CSSM_ALGID_ECDSA:
+                       return CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+               case CSSM_ALGID_DSA:
+                       return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
+               default:
+                       /* punt */
+                       return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+       }
+}
+
+/*
+ * When doing a OPENSSL style wrap operation on a reference key, this
+ * is used to infer the blob type to obtain before the encryption.
+ * App can override this with a 
+ * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT 
+ * context attribute. 
+ */
+CSSM_KEYBLOB_FORMAT opensslRawKeyFormat(
+       CSSM_ALGORITHMS keyAlg)
+{
+       switch(keyAlg) {
+               case CSSM_ALGID_RSA:
+                       return CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+               case CSSM_ALGID_DSA:
+                       return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+               case CSSM_ALGID_ECDSA:
+                       return CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+               default:
+                       /* punt */
+                       return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+       }
+}
+
+/*
+ * Given a key in some kind of openssl format (just subsequent to decryption
+ * during an unwrap), fill in the following header fields:
+ *
+ *     CSSM_KEYBLOB_FORMAT Format
+ *  uint32 LogicalKeySizeInBits
+ */
+void AppleCSPSession::opensslInferKeyHeader( 
+       CssmKey                 &key)
+{
+       CSSM_KEYHEADER &hdr = key.KeyHeader;
+       switch(hdr.AlgorithmId) {
+               case CSSM_ALGID_RSA:
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+                       break;
+               case CSSM_ALGID_DSA:
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+                       break;
+               case CSSM_ALGID_ECDSA:
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+                       break;
+               default:
+                       /* punt */
+                       hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
+                       return;
+       }
+       
+       /* now figure out the key size by finding a provider for this key */
+       CSSM_KEY_SIZE keySize;
+       try {
+               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+               provider->QueryKeySizeInBits(keySize);
+       }
+       catch(...) {
+               /* no recovery possible */
+               throw;
+       }
+       hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
+       return;
+}
+