]> git.saurik.com Git - apple/securityd.git/blobdiff - src/dbcrypto.cpp
securityd-55199.3.tar.gz
[apple/securityd.git] / src / dbcrypto.cpp
index f885440eb13bf1d3e38ef013b56c37238a038323..83d4469d00e3a925726cbd88e2297f89f97cf947 100644 (file)
@@ -3,8 +3,6 @@
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
- * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
 #include <security_cdsa_client/wrapkey.h>
 #include <security_cdsa_utilities/cssmendian.h>
 
-
 using namespace CssmClient;
+using LowLevelMemoryUtilities::fieldOffsetOf;
 
 
+//
+// The CryptoCore constructor doesn't do anything interesting.
+// It just initializes us to "empty".
+//
 DatabaseCryptoCore::DatabaseCryptoCore() : mHaveMaster(false), mIsValid(false)
 {
 }
 
-
 DatabaseCryptoCore::~DatabaseCryptoCore()
 {
     // key objects take care of themselves
@@ -134,6 +135,15 @@ void DatabaseCryptoCore::setup(const DbBlob *blob, CssmClient::Key master)
        mHaveMaster = true;
 }
 
+bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData &data)
+{
+    bool result = false;
+    if (isValid()) {
+        data = mEncryptionKey->keyData();
+        result = true;
+    }
+    return result;
+}
 
 //
 // Given a putative passphrase, determine whether that passphrase
@@ -217,11 +227,11 @@ DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate,
     
     // sign the blob
     CssmData signChunk[] = {
-               CssmData(blob->data(), offsetof(DbBlob, blobSignature)),
+               CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
                CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length())
        };
     CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
-    GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY);     //@@@!!! CRUD
+    GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY);
     signer.key(mSigningKey);
     signer.sign(signChunk, 2, signature);
     assert(signature.length() == sizeof(blob->blobSignature));
@@ -237,7 +247,7 @@ DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate,
 // Throws exceptions if decoding fails.
 // Memory returned in privateAclBlob is allocated and becomes owned by caller.
 //
-void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob)
+void DatabaseCryptoCore::decodeCore(const DbBlob *blob, void **privateAclBlob)
 {
        assert(mHaveMaster);    // must have master key installed
     
@@ -246,8 +256,8 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob)
     decryptor.mode(CSSM_ALGMODE_CBCPadIV8);
     decryptor.padding(CSSM_PADDING_PKCS1);
     decryptor.key(mMasterKey);
-    CssmData ivd(blob->iv, sizeof(blob->iv)); decryptor.initVector(ivd);
-    CssmData cryptoBlob(blob->cryptoBlob(), blob->cryptoBlobLength());
+    CssmData ivd = CssmData::wrap(blob->iv); decryptor.initVector(ivd);
+    CssmData cryptoBlob = CssmData::wrap(blob->cryptoBlob(), blob->cryptoBlobLength());
     CssmData decryptedBlob, remData;
     decryptor.decrypt(cryptoBlob, decryptedBlob, remData);
     DbBlob::PrivateBlob *privateBlob = decryptedBlob.interpretedAs<DbBlob::PrivateBlob>();
@@ -262,8 +272,8 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob)
     
     // verify signature on the whole blob
     CssmData signChunk[] = {
-               CssmData(blob->data(), offsetof(DbBlob, blobSignature)),
-       CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
+               CssmData::wrap(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
+       CssmData::wrap(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
        };
     CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
 #if defined(COMPAT_OSX_10_0)
@@ -272,11 +282,9 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob)
 #endif
     VerifyMac verifier(Server::csp(), verifyAlgorithm);
     verifier.key(mSigningKey);
-    verifier.verify(signChunk, 2, CssmData(blob->blobSignature, sizeof(blob->blobSignature)));
+    verifier.verify(signChunk, 2, CssmData::wrap(blob->blobSignature));
     
     // all checks out; start extracting fields
-    this->mEncryptionKey = mEncryptionKey;
-    this->mSigningKey = mSigningKey;
     if (privateAclBlob) {
         // extract private ACL blob as a separately allocated area
         uint32 blobLength = decryptedBlob.length() - sizeof(DbBlob::PrivateBlob);
@@ -290,35 +298,62 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob)
 }
 
 
+//
+// Make another DatabaseCryptoCore's operational secrets our own.  
+// Intended for keychain synchronization.  
+//
+void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore &src)
+{
+       assert(src.isValid());  // must have called src.decodeCore() first
+       assert(hasMaster());
+       mEncryptionKey = src.mEncryptionKey;
+       mSigningKey = src.mSigningKey;
+    mIsValid = true;
+}
+
 //
 // Encode a key blob
 //
 KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
-    const CssmData &publicAcl, const CssmData &privateAcl) const
+    const CssmData &publicAcl, const CssmData &privateAcl,
+       bool inTheClear) const
 {
-    assert(isValid());         // need our database secrets
-    
-    // create new IV
-    uint8 iv[8];
-    Server::active().random(iv);
-    
-    // extract and hold some header bits the CSP does not want to see
     CssmKey key = inKey;
+       uint8 iv[8];
+       CssmKey wrappedKey;
+
+       if(inTheClear && (privateAcl.Length != 0)) {
+               /* can't store private ACL component in the clear */
+               CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS);
+       }
+       
+    // extract and hold some header bits the CSP does not want to see
     uint32 heldAttributes = key.attributes() & managedAttributes;
     key.clearAttribute(managedAttributes);
        key.setAttribute(forcedAttributes);
     
-    // use a CMS wrap to encrypt the key
-    WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
-    wrap.key(mEncryptionKey);
-    wrap.mode(CSSM_ALGMODE_CBCPadIV8);
-    wrap.padding(CSSM_PADDING_PKCS1);
-    CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd);
-    wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
-        uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
-    CssmKey wrappedKey;
-    wrap(key, wrappedKey, &privateAcl);
-    
+       if(inTheClear) {
+               /* NULL wrap of public key */
+               WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
+               wrap(key, wrappedKey, NULL);
+       }
+       else {
+               assert(isValid());              // need our database secrets
+               
+               // create new IV
+               Server::active().random(iv);
+               
+          // use a CMS wrap to encrypt the key
+               WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
+               wrap.key(mEncryptionKey);
+               wrap.mode(CSSM_ALGMODE_CBCPadIV8);
+               wrap.padding(CSSM_PADDING_PKCS1);
+               CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd);
+               wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
+                       uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
+               wrap(key, wrappedKey, &privateAcl);
+    }
+       
     // stick the held attribute bits back in
        key.clearAttribute(forcedAttributes);
     key.setAttribute(heldAttributes);
@@ -330,7 +365,9 @@ KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
     // assemble the KeyBlob
     memset(blob, 0, sizeof(KeyBlob));  // fill alignment gaps
     blob->initialize();
-    memcpy(blob->iv, iv, sizeof(iv));
+       if(!inTheClear) {
+               memcpy(blob->iv, iv, sizeof(iv));
+       }
     blob->header = key.header();
        h2ni(blob->header);     // endian-correct the header
     blob->wrappedHeader.blobType = wrappedKey.blobType();
@@ -342,17 +379,23 @@ KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
     memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length());
     blob->totalLength = blob->startCryptoBlob + wrappedKey.length();
     
-    // sign the blob
-    CssmData signChunk[] = {
-               CssmData(blob->data(), offsetof(KeyBlob, blobSignature)),
-       CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
-       };
-    CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
-    GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY);     //@@@!!! CRUD
-    signer.key(mSigningKey);
-    signer.sign(signChunk, 2, signature);
-    assert(signature.length() == sizeof(blob->blobSignature));
-    
+       if(inTheClear) {
+               /* indicate that this is cleartext for decoding */
+               blob->setClearTextSignature();
+       }
+       else {
+               // sign the blob
+               CssmData signChunk[] = {
+                       CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)),
+                       CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
+               };
+               CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
+               GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY);  //@@@!!! CRUD
+               signer.key(mSigningKey);
+               signer.sign(signChunk, 2, signature);
+               assert(signature.length() == sizeof(blob->blobSignature));
+    }
+       
     // all done. Clean up
     Server::csp()->allocator().free(wrappedKey);
     return blob;
@@ -364,9 +407,7 @@ KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
 //
 void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
     CssmKey &key, void * &pubAcl, void * &privAcl) const
-{
-    assert(isValid());         // need our database secrets
-    
+{    
     // Assemble the encrypted blob as a CSSM "wrapped key"
     CssmKey wrappedKey;
     wrappedKey.KeyHeader = blob->header;
@@ -377,39 +418,55 @@ void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
     wrappedKey.wrapMode(blob->wrappedHeader.wrapMode);
     wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength());
        
-    // verify signature (check against corruption)
-    CssmData signChunk[] = {
-       CssmData::wrap(blob, offsetof(KeyBlob, blobSignature)),
-       CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
-       };
-    CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
-#if defined(COMPAT_OSX_10_0)
-    if (blob->version() == blob->version_MacOS_10_0)
-        verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY;  // BSafe bug compatibility
-#endif
-    VerifyMac verifier(Server::csp(), verifyAlgorithm);
-    verifier.key(mSigningKey);
-    CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
-    verifier.verify(signChunk, 2, signature);
-    
+       bool inTheClear = blob->isClearText();
+       if(!inTheClear) {
+               // verify signature (check against corruption)
+               assert(isValid());              // need our database secrets
+               CssmData signChunk[] = {
+                       CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)),
+                       CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
+               };
+               CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
+       #if defined(COMPAT_OSX_10_0)
+               if (blob->version() == blob->version_MacOS_10_0)
+                       verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY;   // BSafe bug compatibility
+       #endif
+               VerifyMac verifier(Server::csp(), verifyAlgorithm);
+               verifier.key(mSigningKey);
+               CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
+               verifier.verify(signChunk, 2, signature);
+    }
+       /* else signature indicates cleartext */
+       
     // extract and hold some header bits the CSP does not want to see
     uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes;
    
-    // decrypt the key using an unwrapping operation
-    UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
-    unwrap.key(mEncryptionKey);
-    unwrap.mode(CSSM_ALGMODE_CBCPadIV8);
-    unwrap.padding(CSSM_PADDING_PKCS1);
-    CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd);
-    unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
-        uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
-    CssmData privAclData;
-    wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
-    unwrap(wrappedKey,
-        KeySpec(n2h(blob->header.usage()),
-                       (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
-        key, &privAclData);
-    
+       CssmData privAclData;
+       if(inTheClear) {
+               /* NULL unwrap */
+               UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
+               wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
+               unwrap(wrappedKey,
+                       KeySpec(n2h(blob->header.usage()),
+                               (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
+                       key, &privAclData);
+       }
+       else {
+               // decrypt the key using an unwrapping operation
+               UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
+               unwrap.key(mEncryptionKey);
+               unwrap.mode(CSSM_ALGMODE_CBCPadIV8);
+               unwrap.padding(CSSM_PADDING_PKCS1);
+               CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd);
+               unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
+                       uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
+               wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
+               unwrap(wrappedKey,
+                       KeySpec(n2h(blob->header.usage()),
+                               (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
+                       key, &privAclData);
+    }
+       
     // compare retrieved key headers with blob headers (sanity check)
     // @@@ this should probably be checked over carefully
     CssmKey::Header &real = key.header();
@@ -425,9 +482,15 @@ void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
     // re-insert held bits
     key.header().KeyAttr |= heldAttributes;
     
+       if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) {
+               /* Spoof - cleartext KeyBlob passed off as private key */
+        CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+       }
+       
     // got a valid key: return the pieces
     pubAcl = blob->publicAclBlob();            // points into blob (shared)
-    privAcl = privAclData;                             // was allocated by CSP decrypt
+    privAcl = privAclData;                             // was allocated by CSP decrypt, else NULL for
+                                                                               // cleatext keys
     // key was set by unwrap operation
 }
 
@@ -441,7 +504,8 @@ CssmClient::Key DatabaseCryptoCore::deriveDbMasterKey(const CssmData &passphrase
     CssmClient::DeriveKey makeKey(Server::csp(),
         CSSM_ALGID_PKCS5_PBKDF2, CSSM_ALGID_3DES_3KEY_EDE, 24 * 8);
     makeKey.iterationCount(1000);
-    makeKey.salt(CssmData::wrap(mSalt));
+       CssmData salt = CssmData::wrap(mSalt);
+    makeKey.salt(salt);
     CSSM_PKCS5_PBKDF2_PARAMS params;
     params.Passphrase = passphrase;
     params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;