2  * Copyright (c) 2000-2001,2004 Apple Computer, Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved. 
   8  * This file contains Original Code and/or Modifications of Original Code 
   9  * as defined in and that are subject to the Apple Public Source License 
  10  * Version 2.0 (the 'License'). You may not use this file except in 
  11  * compliance with the License. Please obtain a copy of the License at 
  12  * http://www.opensource.apple.com/apsl/ and read it before using this 
  15  * The Original Code and all software distributed under the License are 
  16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  20  * Please see the License for the specific language governing rights and 
  21  * limitations under the License. 
  23  * @APPLE_LICENSE_HEADER_END@ 
  28 // testacls - ACL-related test cases. 
  30 #include "testclient.h" 
  31 #include "testutils.h" 
  36 // Encodes and decodes Db and Key blobs and all that jazz. 
  40         printf("* Database blob encryption test\n"); 
  41         ClientSession 
ss(CssmAllocator::standard(), CssmAllocator::standard()); 
  43         DbTester 
db1(ss
, "/tmp/one", NULL
, 60, true); 
  44         DbTester 
db2(ss
, "/tmp/two", NULL
, 30, false); 
  46         // encode db1, purge it, decode it again 
  48         ss
.encodeDb(db1
, dbBlob
); 
  49         DbHandle db1a 
= ss
.decodeDb(db1
.dbId
, &nullCred
, dbBlob
); 
  52                 detail("REUSED DB HANDLE ON DECODEDB (probably wrong)"); 
  53         DBParameters savedParams
; 
  54         ss
.getDbParameters(db1a
, savedParams
); 
  55         assert(savedParams
.idleTimeout 
== db1
.params
.idleTimeout
); 
  56         assert(savedParams
.lockOnSleep 
== db1
.params
.lockOnSleep
); 
  57         detail("Database encode/decode passed"); 
  59         // make sure the old handle isn't valid anymore 
  61                 ss
.getDbParameters(db1
, savedParams
); 
  62                 printf("OLD DATABASE HANDLE NOT PURGED (possibly wrong)\n"); 
  63         } catch (const CssmCommonError 
&err
) { 
  64                 detail(err
, "old DB handle rejected"); 
  67     // open db1 a second time (so now there's two db handles for db1) 
  68     DbHandle db1b 
= ss
.decodeDb(db1
.dbId
, &nullCred
, dbBlob
); 
  70     // release both db1 handles and db2 
  79 // Database locks/unlocks etc. 
  83         printf("* Database manipulation test\n"); 
  84     CssmAllocator 
&alloc 
= CssmAllocator::standard(); 
  85         ClientSession 
ss(alloc
, alloc
); 
  87     AutoCredentials 
pwCred(alloc
); 
  88     StringData 
passphrase("two"); 
  89     StringData 
badPassphrase("three"); 
  90     pwCred 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, 
  91         new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
  92         new(alloc
) ListElement(passphrase
)); 
  93     pwCred 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, 
  94         new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
  95         new(alloc
) ListElement(badPassphrase
)); 
  96         // pwCred = (NEW: two, OLD: three) 
  98         DbTester 
db1(ss
, "/tmp/one", NULL
, 30, true); 
  99         DbTester 
db2(ss
, "/tmp/two", &pwCred
, 60, false); 
 100         // db2.passphrase = two 
 102         // encode db1 and re-open it 
 104         ss
.encodeDb(db1
, dbBlob
); 
 105         DbHandle db1b 
= ss
.decodeDb(db1
.dbId
, &nullCred
, dbBlob
); 
 106         if (db1b 
== db1
.dbRef
) 
 107                 detail("REUSED DB HANDLE ON DECODEDB (probably wrong)"); 
 109     // open db1 a third time (so now there's three db handles for db1) 
 110     DbHandle db1c 
= ss
.decodeDb(db1
.dbId
, &nullCred
, dbBlob
); 
 112     // lock them to get started 
 116     // unlock it through user 
 120     ss
.unlock(db1b
);            // 2nd unlock should not prompt 
 121     ss
.lock(db1c
);                      // lock it again 
 123     ss
.unlock(db1
);             // and that should prompt again 
 126     // db2 has a passphrase lock credentials - it'll work without U/I 
 127         db2
.unlock("wrong passphrase");         // pw=two, cred=three 
 128     AutoCredentials 
pwCred2(alloc
); 
 129     pwCred2 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, 
 130         new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 131         new(alloc
) ListElement(passphrase
)); 
 132         // pwCred2 = (OLD: two) 
 133     ss
.authenticateDb(db2
, CSSM_DB_ACCESS_WRITE
, &pwCred2
); // set it 
 137     // now change db2's passphrase 
 139     pwCred2 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, 
 140         new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 141         new(alloc
) ListElement(badPassphrase
)); 
 142         // pwCred2 = (OLD: two, NEW: three) 
 143         db2
.changePassphrase(&pwCred2
); 
 144         // passphrase = three, cred = (OLD: two) 
 146     // encode and re-decode to make sure new data is there 
 148     ss
.encodeDb(db2
, blob2
); 
 149     DbHandle db2a 
= ss
.decodeDb(db2
.dbId
, &pwCred
, blob2
); 
 150         // db2a cred = (OLD: two, NEW: three) 
 152     // now, the *old* cred won't work anymore 
 153         db2
.unlock("old passphrase accepted"); 
 155     // back to the old credentials, which *do* have the (old bad, now good) passphrase 
 158     detail("New passphrase accepted"); 
 160         // clear the credentials (this will prompt; cancel it) 
 161         ss
.authenticateDb(db2
, CSSM_DB_ACCESS_WRITE
, NULL
); 
 163         db2
.unlock("null credential accepted"); 
 166         // fell-swoop from-to change password operation 
 167         StringData 
newPassphrase("hollerith"); 
 168         AutoCredentials 
pwCred3(alloc
); 
 169         pwCred3 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, 
 170                 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 171                 new(alloc
) ListElement(newPassphrase
)); 
 172         pwCred3 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, 
 173                 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 174                 new(alloc
) ListElement(passphrase
)); 
 175         db2
.changePassphrase(&pwCred3
, "accepting original (unchanged) passphrase"); 
 177         AutoCredentials 
pwCred4(alloc
); 
 178         pwCred4 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, 
 179                 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 180                 new(alloc
) ListElement(newPassphrase
)); 
 181         pwCred4 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, 
 182                 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 183                 new(alloc
) ListElement(badPassphrase
)); 
 184         db2
.changePassphrase(&pwCred4
); 
 186         // final status check 
 187         AutoCredentials 
pwCred5(alloc
); 
 188         pwCred5 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, 
 189                 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
), 
 190                 new(alloc
) ListElement(newPassphrase
));  
 191         ss
.authenticateDb(db2
, CSSM_DB_ACCESS_WRITE
, &pwCred5
); 
 193         detail("Final passphrase change verified"); 
 198 // Key encryption tests. 
 202         printf("* Keyblob encryption test\n"); 
 203     CssmAllocator 
&alloc 
= CssmAllocator::standard(); 
 204         ClientSession 
ss(alloc
, alloc
); 
 206     DLDbIdentifier 
dbId1(ssuid
, "/tmp/one", NULL
); 
 207         DBParameters initialParams1 
= { 3600, false }; 
 209     // create a new database 
 210         DbHandle db 
= ss
.createDb(dbId1
, NULL
, NULL
, initialParams1
); 
 211         detail("Database created"); 
 213         // establish an ACL for the key 
 214         StringData 
theAclPassword("Strenge Geheimsache"); 
 215         AclEntryPrototype initialAcl
; 
 216         initialAcl
.TypedSubject 
= TypedList(alloc
, CSSM_ACL_SUBJECT_TYPE_PASSWORD
, 
 217                 new(alloc
) ListElement(theAclPassword
)); 
 218         AclEntryInput 
initialAclInput(initialAcl
); 
 220     AutoCredentials 
cred(alloc
); 
 221     cred 
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_PASSWORD
, 
 222         new(alloc
) ListElement(theAclPassword
)); 
 225         const CssmCryptoData 
seed(StringData("Farmers' day")); 
 226         FakeContext 
genContext(CSSM_ALGCLASS_KEYGEN
, CSSM_ALGID_DES
, 
 227                 &::Context::Attr(CSSM_ATTRIBUTE_KEY_LENGTH
, 64), 
 228                 &::Context::Attr(CSSM_ATTRIBUTE_SEED
, seed
), 
 231     CssmKey::Header header
; 
 232     ss
.generateKey(db
, genContext
, CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT
, 
 233         CSSM_KEYATTR_RETURN_REF 
| CSSM_KEYATTR_PERMANENT
, 
 234         /*cred*/NULL
, &initialAclInput
, key
, header
); 
 235         detail("Key generated"); 
 237     // encrypt with the key 
 238     StringData 
clearText("Yet another boring cleartext sample string text sequence."); 
 239     StringData 
iv("Aardvark"); 
 240     CssmKey nullKey
; memset(&nullKey
, 0, sizeof(nullKey
)); 
 241         FakeContext 
cryptoContext(CSSM_ALGCLASS_SYMMETRIC
, CSSM_ALGID_DES
, 
 242                 &::Context::Attr(CSSM_ATTRIBUTE_KEY
, nullKey
), 
 243                 &::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR
, iv
), 
 244                 &::Context::Attr(CSSM_ATTRIBUTE_MODE
, CSSM_ALGMODE_CBC_IV8
), 
 245                 &::Context::Attr(CSSM_ATTRIBUTE_PADDING
, CSSM_PADDING_PKCS1
), 
 246         &::Context::Attr(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS
, cred
), 
 249         ss
.encrypt(cryptoContext
, key
, clearText
, cipherText
); 
 250         detail("Plaintext encrypted with original key"); 
 252     // encode the key and release it 
 254     ss
.encodeKey(key
, blob
); 
 256     detail("Key encoded and released"); 
 258     // decode it again, re-introducing it 
 259     CssmKey::Header decodedHeader
; 
 260     KeyHandle key2 
= ss
.decodeKey(db
, blob
, decodedHeader
); 
 261     detail("Key decoded"); 
 263     // decrypt with decoded key 
 265     ss
.decrypt(cryptoContext
, key2
, cipherText
, recovered
); 
 266     assert(recovered 
== clearText
); 
 267     detail("Decoded key correctly decrypts ciphertext"); 
 269     // check a few header fields 
 270     if (!memcmp(&header
, &decodedHeader
, sizeof(header
))) { 
 271         detail("All header fields match"); 
 273         assert(header
.algorithm() == decodedHeader
.algorithm()); 
 274         assert(header
.blobType() == decodedHeader
.blobType()); 
 275         assert(header
.blobFormat() == decodedHeader
.blobFormat()); 
 276         assert(header
.keyClass() == decodedHeader
.keyClass()); 
 277         assert(header
.attributes() == decodedHeader
.attributes()); 
 278         assert(header
.usage() == decodedHeader
.usage()); 
 279         printf("Some header fields differ (probably okay)\n"); 
 282     // make sure we need the credentials (destructive) 
 283     memset(&cred
, 0, sizeof(cred
)); 
 285         ss
.decrypt(cryptoContext
, key2
, cipherText
, recovered
); 
 286         error("RESTORED ACL FAILS TO RESTRICT"); 
 287     } catch (CssmError 
&err
) { 
 288         detail(err
, "Restored key restricts access properly");