]>
Commit | Line | Data |
---|---|---|
866f8763 A |
1 | // |
2 | // Copyright 2016 Apple. All rights reserved. | |
3 | // | |
4 | ||
5 | #import <Foundation/Foundation.h> | |
6 | #import <Security/Security.h> | |
7 | #import <Security/SecItemPriv.h> | |
8 | #import <Security/SecKeyPriv.h> | |
9 | #if !TARGET_OS_OSX | |
10 | #import "MobileGestalt.h" | |
11 | #endif | |
12 | ||
13 | #import "shared_regressions.h" | |
14 | ||
15 | static id generateKey(id keyType) { | |
16 | id accessControl = (__bridge_transfer id)SecAccessControlCreateWithFlags(NULL, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAccessControlPrivateKeyUsage, NULL); | |
17 | NSDictionary *keyAttributes = @{ (id)kSecAttrTokenID : (id)kSecAttrTokenIDAppleKeyStore, | |
18 | (id)kSecAttrKeyType : keyType, | |
19 | (id)kSecAttrAccessControl : accessControl, | |
20 | (id)kSecAttrIsPermanent : @NO }; | |
21 | NSError *error; | |
22 | id key = (__bridge_transfer id)SecKeyCreateRandomKey((CFDictionaryRef)keyAttributes, (void *)&error); | |
23 | ok(key, "failed to create random key %@", error); | |
24 | return key; | |
25 | } | |
26 | ||
27 | static void secKeySepTest(BOOL testPKA) { | |
28 | NSArray *keyTypes; | |
29 | if (testPKA) { | |
30 | keyTypes = @[(id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyTypeECSECPrimeRandomPKA, (id)kSecAttrKeyTypeSecureEnclaveAttestation]; | |
31 | } else { | |
32 | keyTypes = @[(id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyTypeSecureEnclaveAttestation]; | |
33 | } | |
34 | for (id keyType in keyTypes) { | |
35 | id privateKey = generateKey((id)keyType); | |
36 | ok(privateKey, "failed to create key '%@'", keyType); | |
37 | id publicKey = (__bridge_transfer id)SecKeyCopyPublicKey((SecKeyRef)privateKey); | |
38 | ||
39 | NSArray *attestaionKeyTypes = @[@(kSecKeyAttestationKeyTypeSIK), @(kSecKeyAttestationKeyTypeGID)]; | |
40 | for (NSNumber *attestationKeyType in attestaionKeyTypes) { | |
41 | id attestationKey = (__bridge_transfer id)SecKeyCopyAttestationKey([attestationKeyType unsignedIntValue], NULL); | |
42 | ok(attestationKey, "failed to create attestaion key '%@'", attestationKeyType); | |
43 | NSError *error; | |
44 | if (![keyType isEqual:(id)kSecAttrKeyTypeSecureEnclaveAttestation]) { | |
45 | const char rawData[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
46 | NSData *dataToSign = [NSData dataWithBytes:rawData length:sizeof(rawData)]; | |
47 | NSData *signedData = (__bridge_transfer NSData*)SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (void *)&error); | |
48 | ok(signedData, "failed to sign data, error %@", error); | |
49 | error = nil; | |
50 | ok(SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (__bridge CFDataRef)signedData, (void *)&error), | |
51 | "failed to verify data '%@'", error); | |
52 | ||
53 | // Try signing large data. | |
54 | dataToSign = [NSMutableData dataWithLength:10 * 1024 * 1024]; | |
55 | error = nil; | |
56 | signedData = (__bridge_transfer NSData*)SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (void *)&error); | |
57 | ok(signedData, "failed to sign data, error %@", error); | |
58 | error = nil; | |
59 | ok(SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (__bridge CFDataRef)signedData, (void *)&error), | |
60 | "failed to verify data '%@'", error); | |
61 | } | |
62 | NSData *attestationData = (__bridge_transfer NSData *)SecKeyCreateAttestation((__bridge SecKeyRef)attestationKey, (__bridge SecKeyRef)privateKey, (void *)&error); | |
63 | ok(attestationData, "failed to attest key '%@'", error); | |
64 | } | |
65 | ||
66 | NSDictionary *keyAttrs = (__bridge_transfer NSDictionary *)SecKeyCopyAttributes((SecKeyRef)privateKey); | |
67 | NSData *keyBlob = keyAttrs[(id)kSecAttrTokenOID]; | |
68 | ||
69 | NSDictionary *params = @{ (id)kSecAttrTokenID : (id)kSecAttrTokenIDAppleKeyStore, | |
70 | (id)kSecAttrTokenOID : keyBlob, | |
71 | (id)kSecReturnRef : @YES }; | |
72 | ||
73 | privateKey = nil; | |
74 | NSError *error; | |
75 | privateKey = (__bridge_transfer id)SecKeyCreateWithData((__bridge CFDataRef)keyBlob, (__bridge CFDictionaryRef)params, (void *)&error); | |
76 | ok(privateKey, "failed to create key with data '%@'", error); | |
77 | // <rdar://problem/30651629> SecItemAdd fails to create SecKey from aks key blob | |
78 | // | |
79 | // ok_status(SecItemAdd((__bridge CFDictionaryRef)params, (void *)&privateKey), "failed to create key from aks blob"); | |
80 | // ok_status(SecItemDelete((__bridge CFDictionaryRef) @{(id)kSecValueRef : privateKey}), "failed to delete key from aks blob"); | |
81 | } | |
82 | } | |
83 | ||
84 | static void attestationTest(void) { | |
85 | NSError *error; | |
86 | id privKey = generateKey((id)kSecAttrKeyTypeECSECPrimeRandom); | |
87 | id uik = generateKey((id)kSecAttrKeyTypeSecureEnclaveAttestation); | |
88 | id sik = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeSIK, (void *)&error)); | |
89 | ok(sik != nil, "get SIk key: %@", error); | |
90 | ||
91 | error = nil; | |
92 | NSData *attSIKPlain = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)uik, (void *)&error)); | |
93 | ok(attSIKPlain != nil, "SIK attesting UIK, no nonce: %@", error); | |
94 | ||
95 | error = nil; | |
96 | NSData *attUIKPlain = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)uik, (__bridge SecKeyRef)privKey, (void *)&error)); | |
97 | ok(attUIKPlain != nil, "UIK attesting privKey, no nonce: %@", error); | |
98 | ||
99 | error = nil; | |
100 | NSData *nonce = [@"TESTnonce" dataUsingEncoding:NSUTF8StringEncoding]; | |
101 | ok(SecKeySetParameter((__bridge SecKeyRef)sik, kSecKeyParameterSETokenAttestationNonce, (__bridge CFPropertyListRef)nonce, (void *)&error), "Set nonce to SIK: %@", error); | |
102 | NSData *attSIKNonce = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)uik, (void *)&error)); | |
103 | ok(attSIKNonce != nil, "SIK attesting UIK, with nonce: %@", error); | |
104 | // NSRange found = [attSIKNonce rangeOfData:nonce options:0 range:NSMakeRange(0, attSIKNonce.length)]; | |
105 | // ok(found.location != NSNotFound, "nonce found in SIK-attested data"); | |
106 | ||
107 | error = nil; | |
108 | ok(SecKeySetParameter((__bridge SecKeyRef)uik, kSecKeyParameterSETokenAttestationNonce, (__bridge CFPropertyListRef)nonce, (void *)&error), "Set nonce to UIK: %@", error); | |
109 | NSData *attUIKNonce = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)uik, (__bridge SecKeyRef)privKey, (void *)&error)); | |
110 | ok(attUIKNonce != nil, "SIK attesting UIK, with nonce: %@", error); | |
111 | // found = [attUIKNonce rangeOfData:nonce options:0 range:NSMakeRange(0, attUIKNonce.length)]; | |
112 | // ok(found.location != NSNotFound, "nonce found in UIK-attested data"); | |
113 | } | |
114 | ||
115 | int si_44_seckey_aks(int argc, char *const *argv) { | |
116 | @autoreleasepool { | |
117 | BOOL testPKA = YES; | |
118 | #if !TARGET_OS_OSX | |
119 | id hasPKA = (__bridge_transfer id)MGCopyAnswer(kMGQHasPKA, NULL); | |
120 | if(![hasPKA isKindOfClass:NSNumber.class] || ![(NSNumber *)hasPKA boolValue]) { | |
121 | testPKA = NO; | |
122 | } | |
123 | #else | |
124 | testPKA = NO; | |
125 | #endif | |
126 | plan_tests(testPKA ? 46 : 31); | |
127 | secKeySepTest(testPKA); | |
128 | attestationTest(); | |
129 | return 0; | |
130 | } | |
131 | } |