--- /dev/null
+/*
+ * Copyright (c) 2000-2001,2003-2004 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The 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.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// Tester - test driver for securityserver client side.
+//
+#include "testclient.h"
+#include "testutils.h"
+
+
+//
+// Simple run-through.
+// This generates an RSA key, tests cleartext retrieval, signs a message,
+// and veries it both ways.
+// This is a basic integrity regression for the SecurityServer.
+//
+void signWithRSA()
+{
+ printf("* RSA key signing test\n");
+ CSP csp(gGuidAppleCSP);
+ ClientSession ss(CssmAllocator::standard(), CssmAllocator::standard());
+ StringData data("To sign or not to sign, is that the question?");
+
+ // set up dummy credentials
+ CssmKey dummyKey; memset(&dummyKey, 0, sizeof(dummyKey));
+ CssmData nullData;
+
+ // generate a key
+ detail("Asking for RSA key generation");
+ KeyHandle publicKey, privateKey;
+ const CssmCryptoData seed(StringData("Seed ye well, my friend, and ye shall reap..."));
+ FakeContext genContext(CSSM_ALGCLASS_KEYGEN, CSSM_ALGID_RSA,
+ &::Context::Attr(CSSM_ATTRIBUTE_KEY_LENGTH, 512),
+ &::Context::Attr(CSSM_ATTRIBUTE_SEED, seed),
+ NULL);
+ CssmKey::Header pubHeader, privHeader;
+ ss.generateKey(noDb, genContext,
+ CSSM_KEYUSE_VERIFY, CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_DATA,
+ CSSM_KEYUSE_SIGN, CSSM_KEYATTR_SENSITIVE,
+ NULL/*cred*/, NULL/*owner*/, publicKey, pubHeader, privateKey, privHeader);
+ detail("Key pair generated");
+
+ // retrieve the public key
+ CssmKey cpk;
+ FakeContext wrapContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_NONE, 0);
+ ss.wrapKey(wrapContext, noKey, publicKey, &nullCred, NULL, cpk);
+ Key clearPublicKey(csp, cpk);
+ detail("Retrieved public key");
+
+ // make sure we can't retrieve the private key
+ CssmKey clearPrivateKey;
+ try {
+ ss.wrapKey(wrapContext, noKey, privateKey, NULL/*cred*/, NULL, clearPrivateKey);
+ error("SecurityServer ACTUALLY gave us the PRIVATE key bits!");
+ } catch (CssmError &err) {
+ detail(err, "Private key retrieval properly rejected");
+ }
+
+ // sign a message
+ CssmData signature;
+ FakeContext signContext(CSSM_ALGCLASS_SIGNATURE, CSSM_ALGID_SHA1WithRSA,
+ &::Context::Attr(CSSM_ATTRIBUTE_KEY, dummyKey),
+ NULL);
+ ss.generateSignature(signContext, privateKey, data, signature);
+ detail("Signature generated by SecurityServer");
+
+ // verify the signature (local)
+ {
+ Verify verifier(csp, CSSM_ALGID_SHA1WithRSA);
+ verifier.key(clearPublicKey);
+ verifier.verify(data, signature);
+ detail("Signature verified locally");
+ }
+
+ // verify the signature (SS)
+ ss.verifySignature(signContext, publicKey, data, signature);
+ detail("Signature verified by SecurityServer");
+
+ // falsify the signature (SS)
+ DataBuffer<200> falseData;
+ memcpy(falseData.data(), data.data(), data.length());
+ falseData.length(data.length());
+ ((char *)falseData)[3] = '?'; // alter message
+ try {
+ ss.verifySignature(signContext, publicKey, falseData, signature);
+ error("Altered message incorrectly verifies");
+ } catch (CssmError &err) {
+ if (err.cssmError() == CSSMERR_CSP_VERIFY_FAILED)
+ detail("Verify of altered message successfully failed");
+ else
+ error(err, "Unexpected exception on verify failure test");
+ }
+}
+
+
+//
+// Encrypt with DES
+//
+void desEncryption()
+{
+ printf("* DES encryption test\n");
+ ClientSession ss(CssmAllocator::standard(), CssmAllocator::standard());
+ CSP csp(gGuidAppleCSP);
+
+ StringData clearText("Insert witty quotation here.");
+ StringData iv("abcdefgh");
+
+ // make up a DES key
+ StringData keyBits(strdup("Wallaby!"));
+ CssmKey keyForm(keyBits);
+ keyForm.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
+ keyForm.header().BlobType = CSSM_KEYBLOB_RAW;
+ keyForm.header().AlgorithmId = CSSM_ALGID_DES;
+ keyForm.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
+ Key key(csp, keyForm);
+
+ // encrypt locally
+ DataBuffer<200> localCipher;
+ Encrypt localCrypt(csp, CSSM_ALGID_DES);
+ localCrypt.mode(CSSM_ALGMODE_CBC_IV8);
+ localCrypt.padding(CSSM_PADDING_PKCS1);
+ localCrypt.initVector(iv);
+ localCrypt.key(key);
+ CssmData remData;
+ size_t localLen = localCrypt.encrypt(clearText, localCipher, remData);
+ if (remData)
+ error("LOCAL ENCRYPTION OVERFLOWED");
+ localCipher.length(localLen);
+ detail("Locally encrypted %ld bytes", localLen);
+
+ // wrap in the key
+ CssmData unwrappedData;
+ ResourceControlContext owner;
+ FakeContext unwrapContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_NONE, 0);
+ KeyHandle keyRef;
+ CssmKey::Header keyHeader;
+ ss.unwrapKey(noDb, unwrapContext, noKey, noKey,
+ key,
+ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+ CSSM_KEYATTR_RETURN_DEFAULT,
+ NULL/*cred*/, NULL/*owner*/, unwrappedData, keyRef, keyHeader);
+ detail("Placed key into SecurityServer; handle=%lx", keyRef);
+
+ // encrypt remotely and compare
+ const CssmKey &tKey = key;
+ FakeContext cryptoContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_DES,
+ &::Context::Attr(CSSM_ATTRIBUTE_KEY, keyForm),
+ &::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR, iv),
+ &::Context::Attr(CSSM_ATTRIBUTE_MODE, CSSM_ALGMODE_CBC_IV8),
+ &::Context::Attr(CSSM_ATTRIBUTE_PADDING, CSSM_PADDING_PKCS1),
+ NULL);
+ CssmData remoteCipher;
+ ss.encrypt(cryptoContext, keyRef, clearText, remoteCipher);
+ detail("Plaintext encrypted on SecurityServer");
+ if (remoteCipher == localCipher)
+ detail("Ciphertexts verified");
+ else
+ error("CIPHERTEXTS DIFFER");
+
+ // decrypt in SecurityServer
+ DataBuffer<200> clearRecovered;
+ ss.decrypt(cryptoContext, keyRef, localCipher, clearRecovered);
+ detail("Decrypted ciphertext in SecurityServer");
+ if (clearRecovered == clearText)
+ detail("Plaintext recovered");
+ else
+ error("PLAINTEXT MISMATCH");
+}
+