]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_apple_cspdl/lib/SSKey.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_cspdl / lib / SSKey.cpp
diff --git a/libsecurity_apple_cspdl/lib/SSKey.cpp b/libsecurity_apple_cspdl/lib/SSKey.cpp
new file mode 100644 (file)
index 0000000..6400b62
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2000-2001,2008 Apple 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.
+ */
+
+
+//
+// SSKey - reference keys for the security server
+//
+#include "SSKey.h"
+
+#include "SSCSPSession.h"
+#include "SSCSPDLSession.h"
+#include "SSDatabase.h"
+#include "SSDLSession.h"
+#include <security_cdsa_utilities/KeySchema.h>
+#include <security_cdsa_plugin/cssmplugin.h>
+
+using namespace CssmClient;
+using namespace SecurityServer;
+
+// Constructor for a Security Server generated key.
+SSKey::SSKey(SSCSPSession &session, KeyHandle keyHandle, CssmKey &ioKey,
+                        SSDatabase &inSSDatabase, uint32 inKeyAttr,
+                        const CssmData *inKeyLabel)
+: ReferencedKey(session.mSSCSPDLSession),
+mAllocator(session), mKeyHandle(keyHandle),
+mClientSession(session.clientSession())
+{
+       CssmKey::Header &header = ioKey.header();
+       if (inKeyAttr & CSSM_KEYATTR_PERMANENT)
+       {
+               if (!inSSDatabase)
+                       CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);
+
+               // EncodeKey and store it in the db.
+               CssmDataContainer blob(mAllocator);
+               clientSession().encodeKey(keyHandle, blob);
+
+               assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION);
+               switch (header.KeyClass)
+               {
+               case CSSM_KEYCLASS_PUBLIC_KEY:
+                       mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
+                       break;
+               case CSSM_KEYCLASS_PRIVATE_KEY:
+                       mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
+                       break;
+               case CSSM_KEYCLASS_SESSION_KEY:
+                       mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
+                       break;
+               default:
+                       CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+               }
+
+               CssmData label;
+               if (inKeyLabel)
+                       label = *inKeyLabel;
+
+               CssmData none;
+               // We store the keys real CSP guid on disk
+               CssmGuidData creatorGuid(header.CspId);
+               CssmDateData startDate(header.StartDate);
+               CssmDateData endDate(header.EndDate);
+
+               DbAttributes attributes(inSSDatabase);
+               attributes.recordType(mRecordType);
+               attributes.add(KeySchema::KeyClass, mRecordType);
+               attributes.add(KeySchema::PrintName, label);
+               attributes.add(KeySchema::Alias, none);
+               attributes.add(KeySchema::Permanent,
+                                          header.attribute(CSSM_KEYATTR_PERMANENT));
+               attributes.add(KeySchema::Private,
+                                          header.attribute(CSSM_KEYATTR_PRIVATE));
+               attributes.add(KeySchema::Modifiable,
+                                          header.attribute(CSSM_KEYATTR_MODIFIABLE));
+               attributes.add(KeySchema::Label, label);
+               attributes.add(KeySchema::ApplicationTag, none);
+               attributes.add(KeySchema::KeyCreator, creatorGuid);
+               attributes.add(KeySchema::KeyType, header.AlgorithmId);
+               attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits);
+               // @@@ Get the real effective key size.
+               attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits);
+               attributes.add(KeySchema::StartDate, startDate);
+               attributes.add(KeySchema::EndDate, endDate);
+               attributes.add(KeySchema::Sensitive,
+                                          header.attribute(CSSM_KEYATTR_SENSITIVE));
+               attributes.add(KeySchema::AlwaysSensitive,
+                                          header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE));
+               attributes.add(KeySchema::Extractable,
+                                          header.attribute(CSSM_KEYATTR_EXTRACTABLE));
+               attributes.add(KeySchema::NeverExtractable,
+                                          header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE));
+               attributes.add(KeySchema::Encrypt,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT));
+               attributes.add(KeySchema::Decrypt,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT));
+               attributes.add(KeySchema::Derive,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE));
+               attributes.add(KeySchema::Sign,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN));
+               attributes.add(KeySchema::Verify,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY));
+               attributes.add(KeySchema::SignRecover,
+                                          header.useFor(CSSM_KEYUSE_ANY
+                                                                        | CSSM_KEYUSE_SIGN_RECOVER));
+               attributes.add(KeySchema::VerifyRecover,
+                                          header.useFor(CSSM_KEYUSE_ANY
+                                                                        | CSSM_KEYUSE_VERIFY_RECOVER));
+               attributes.add(KeySchema::Wrap,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP));
+               attributes.add(KeySchema::Unwrap,
+                                          header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP));
+
+               // @@@ Fixme
+               mUniqueId = inSSDatabase->insert(mRecordType, &attributes, &blob,
+                                                                                true);
+       }
+
+       header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
+       makeReferenceKey(mAllocator, keyReference(), ioKey);
+}
+
+// Constructor for a key retrived from a Db.
+SSKey::SSKey(SSDLSession &session, CssmKey &ioKey, SSDatabase &inSSDatabase,
+                        const SSUniqueRecord &uniqueId, CSSM_DB_RECORDTYPE recordType,
+                        CssmData &keyBlob)
+: ReferencedKey(session.mSSCSPDLSession),
+mAllocator(session.allocator()), mKeyHandle(noKey), mUniqueId(uniqueId),
+mRecordType(recordType),
+mClientSession(session.clientSession())
+{
+       CssmKey::Header &header = ioKey.header();
+       memset(&header, 0, sizeof(header)); // Clear key header
+
+       if (!mUniqueId || !mUniqueId->database())
+               CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
+
+       header.HeaderVersion = CSSM_KEYHEADER_VERSION;
+       switch (mRecordType)
+       {
+       case CSSM_DL_DB_RECORD_PUBLIC_KEY:
+               header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
+               break;
+       case CSSM_DL_DB_RECORD_PRIVATE_KEY:
+               header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
+               break;
+       case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
+               header.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
+               break;
+       default:
+               CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+       }
+
+       DbAttributes attributes(mUniqueId->database());
+       attributes.recordType(mRecordType);
+       attributes.add(KeySchema::KeyClass);                    // 0
+       attributes.add(KeySchema::Permanent);                   // 1
+       attributes.add(KeySchema::Private);                     // 2
+       attributes.add(KeySchema::Modifiable);                  // 3
+       attributes.add(KeySchema::KeyCreator);                  // 4
+       attributes.add(KeySchema::KeyType);                     // 5
+       attributes.add(KeySchema::KeySizeInBits);               // 6
+       attributes.add(KeySchema::StartDate);                   // 7
+       attributes.add(KeySchema::EndDate);                     // 8
+       attributes.add(KeySchema::Sensitive);                   // 9
+       attributes.add(KeySchema::AlwaysSensitive);     // 10
+       attributes.add(KeySchema::Extractable);         // 11
+       attributes.add(KeySchema::NeverExtractable);    // 12
+       attributes.add(KeySchema::Encrypt);                     // 13
+       attributes.add(KeySchema::Decrypt);                     // 14
+       attributes.add(KeySchema::Derive);                              // 15
+       attributes.add(KeySchema::Sign);                                // 16
+       attributes.add(KeySchema::Verify);                              // 17
+       attributes.add(KeySchema::SignRecover);         // 18
+       attributes.add(KeySchema::VerifyRecover);               // 19
+       attributes.add(KeySchema::Wrap);                                // 20
+       attributes.add(KeySchema::Unwrap);                              // 21
+
+       mUniqueId->get(&attributes, NULL);
+
+       // Assert that the mRecordType matches the KeyClass attribute.
+       if (mRecordType != uint32(attributes[0]))
+               CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+
+       header.AlgorithmId = attributes[5]; // KeyType
+    header.LogicalKeySizeInBits = attributes[6]; // KeySizeInBits
+
+       if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT);
+       if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE);
+       if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE);
+       if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE);
+       if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE);
+       if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE);
+       if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE);
+
+       if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT);
+       if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT);
+       if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE);
+       if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN);
+       if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY);
+       if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER);
+       if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER);
+       if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP);
+       if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP);
+
+       // If all usages are allowed set usage to CSSM_KEYUSE_ANY
+       if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT
+                                                  | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN
+                                                  | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
+                                                  | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP
+                                                  | CSSM_KEYUSE_UNWRAP))
+               header.usage(CSSM_KEYUSE_ANY); 
+
+       if (!attributes[7].size() || !attributes[8].size())
+               CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+
+    header.StartDate = attributes[7].at<CSSM_DATE>(0);
+    header.EndDate = attributes[8].at<CSSM_DATE>(0);
+
+       makeReferenceKey(mAllocator, keyReference(), ioKey);
+       header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
+}
+
+SSKey::~SSKey()
+{
+       if (mKeyHandle != noKey)
+               clientSession().releaseKey(mKeyHandle);
+}
+
+void
+SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey,
+                       CSSM_BOOL deleteKey)
+{
+       freeReferenceKey(mAllocator, ioKey);
+       if (deleteKey)
+       {
+               if (!mUniqueId || !mUniqueId->database())
+                       CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+       
+               // @@@ Evaluate accessCred against Db acl.
+               // What should we do with accessCred?  Reauthenticate
+               // mUniqueId->database()?
+               mUniqueId->deleteRecord();
+       }
+
+       if (mKeyHandle != noKey)
+       {
+               clientSession().releaseKey(mKeyHandle);
+               mKeyHandle = noKey;
+       }
+}
+
+SecurityServer::ClientSession &
+SSKey::clientSession()
+{
+       return mClientSession;
+}
+
+KeyHandle SSKey::optionalKeyHandle() const
+{
+       return mKeyHandle;
+}
+
+KeyHandle
+SSKey::keyHandle()
+{
+       if (mKeyHandle == noKey)
+       {
+               // Deal with uninstantiated keys.
+               if (!mUniqueId || !mUniqueId->database())
+                       CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
+
+               CssmDataContainer blob(mAllocator);
+               mUniqueId->get(NULL, &blob);
+               CssmKey::Header dummyHeader; // @@@ Unused
+               mKeyHandle =
+                       clientSession().decodeKey(mUniqueId->database().dbHandle(), blob,
+                                                                         dummyHeader);
+
+               // @@@ Check decoded header against returned header
+       }
+
+       return  mKeyHandle;
+}
+
+//
+// ACL retrieval and change operations
+//
+void
+SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE &owner, Allocator &allocator)
+{
+       clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner),
+                                                               allocator);
+}
+
+void
+SSKey::changeOwner(const AccessCredentials &accessCred,
+                                  const AclOwnerPrototype &newOwner)
+{
+       clientSession().changeKeyOwner(keyHandle(), accessCred, newOwner);
+       didChangeAcl();
+}
+
+void
+SSKey::getAcl(const char *selectionTag, uint32 &numberOfAclInfos,
+                         AclEntryInfo *&aclInfos, Allocator &allocator)
+{
+       clientSession().getKeyAcl(keyHandle(), selectionTag, numberOfAclInfos,
+                                                         aclInfos, allocator);
+}
+
+void
+SSKey::changeAcl(const AccessCredentials &accessCred, const AclEdit &aclEdit)
+{
+       clientSession().changeKeyAcl(keyHandle(), accessCred, aclEdit);
+       didChangeAcl();
+}
+
+void
+SSKey::didChangeAcl()
+{
+       if (mUniqueId == true)
+       {
+           secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", mKeyHandle);
+               // The key is persistent, make the change on disk.
+               CssmDataContainer keyBlob(mAllocator);
+               clientSession().encodeKey(keyHandle(), keyBlob);
+               mUniqueId->modify(mRecordType, NULL, &keyBlob, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
+       }
+       else
+       {
+           secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", mKeyHandle);
+       }
+}