1/* 2 * Copyright (c) 2011,2013-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25/* 26 * si-40-seckey.c 27 * Security 28 * 29 * Copyright (c) 2007-2009,2013-2014 Apple Inc. All Rights Reserved. 30 * 31 */ 32#include <TargetConditionals.h> 33#include <CoreFoundation/CoreFoundation.h> 34#include <Security/Security.h> 35#include <Security/SecKeyPriv.h> 36 37#if 0 38#include <Security/SecCertificate.h> 39#include <Security/SecCertificateInternal.h> 40#include <Security/SecKey.h> 41#include <Security/SecKeyPriv.h> 42#include <Security/SecItem.h> 43#include <Security/SecAsn1Types.h> 44#include <Security/oidsalg.h> 45#include <Security/SecureTransport.h> 46#include <Security/SecRandom.h> 47#include <CommonCrypto/CommonDigest.h> 48#include <libDER/libDER.h> 49#include <stdlib.h> 50#include <unistd.h> 51#endif 52 53 54#include "keychain_regressions.h" 55#include "utilities/SecCFRelease.h" 56 57 58#if TARGET_OS_IPHONE 59static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) { 60 uint8_t dataToDigest[256]; 61 size_t dataToDigestLen = sizeof(dataToDigest); 62 size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize); 63 uint8_t sig[sigLen]; 64 65 DERItem oid; 66 oid.length = algId->algorithm.Length; 67 oid.data = algId->algorithm.Data; 68 69 /* Get the oid in decimal for display purposes. */ 70 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid); 71 char oidBuf[40]; 72 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8); 73 CFRelease(oidStr); 74 75SKIP: { 76 OSStatus status; 77 78 /* Time to sign. */ 79 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen, 80 sig, &sigLen), 81 "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8); 82 83 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess); 84 85 /* Verify the signature we just made. */ 86 ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 87 sig, sigLen), "digest and verify"); 88 /* Invalidate the signature. */ 89 sig[0] ^= 0xff; 90 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 91 sig, sigLen), errSSLCrypto, "digest and verify bad sig"); 92 sig[0] ^= 0xff; 93 dataToDigest[0] ^= 0xff; 94 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 95 sig, sigLen), errSSLCrypto, "digest and verify bad digest"); 96} 97} 98 99static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) { 100 static const SecAsn1Oid *oids[] = { 101 &CSSMOID_ECDSA_WithSHA1, 102#if 0 103 &CSSMOID_ECDSA_WithSHA224, 104 &CSSMOID_ECDSA_WithSHA256, 105 &CSSMOID_ECDSA_WithSHA384, 106 &CSSMOID_ECDSA_WithSHA512, 107#endif 108 }; 109 110 uint32_t ix; 111 SecAsn1AlgId algId = {}; 112 for (ix = 0; ix < sizeof(oids) / sizeof(*oids); ++ix) { 113 if (oids[ix]) { 114 algId.algorithm = *oids[ix]; 115 } else { 116 algId.algorithm.Length = 0; 117 algId.algorithm.Data = NULL; 118 } 119 120 testdigestandsignalg(privKey, pubKey, &algId); 121 } 122} 123#endif 124 125 126#if !TARGET_OS_IPHONE 127/* This is part of Security.framework on iOS */ 128 129enum { 130 // kSecKeyKeySizeInBits = 0, // already exists on osx 131 kSecKeySignatureSize = 101, 132 kSecKeyEncryptedDataSize = 102, 133 // More might belong here, but we aren't settled on how 134 // to take into account padding and/or digest types. 135}; 136 137static 138size_t SecKeyGetSize(SecKeyRef key, int whichSize) 139{ 140 /* SecKeyGetBlockSize return the signature size on OS X -- smh */ 141 size_t result = SecKeyGetBlockSize(key); 142 143 result = (result - 2)/2 - 3; 144 145 /* in this test, this is always an ECDSA key */ 146 switch (whichSize) { 147 case kSecKeyEncryptedDataSize: 148 result = 0; 149 break; 150 case kSecKeySignatureSize: 151 result = (result >= 66 ? 9 : 8) + 2 * result; 152 break; 153 case kSecKeyKeySizeInBits: 154 if (result >= 66) 155 return 521; 156 } 157 158 if (whichSize == kSecKeyKeySizeInBits) 159 result *= 8; 160 161 return result; 162 163} 164#endif 165 166 167static void testkeygen(size_t keySizeInBits) { 168 SecKeyRef pubKey = NULL, privKey = NULL; 169 size_t keySizeInBytes = (keySizeInBits + 7) / 8; 170 CFNumberRef kzib; 171 172 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits); 173 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 174 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC); 175 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); 176 177 OSStatus status; 178 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), 179 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits, 180 keySizeInBytes); 181 CFRelease(kzib); 182 CFRelease(kgp); 183 184SKIP: { 185 skip("keygen failed", 8, status == errSecSuccess); 186 ok(pubKey, "pubkey returned"); 187 ok(privKey, "privKey returned"); 188 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); 189 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); 190 191 /* Sign something. */ 192 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; 193 uint8_t sig[8+2*keySizeInBytes]; 194 size_t sigLen = sizeof(sig); 195 ok_status(SecKeyRawSign(privKey, kSecPaddingNone, 196 something, sizeof(something), sig, &sigLen), "sign something"); 197 ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone, 198 something, sizeof(something), sig, sigLen), "verify sig on something"); 199 200#if TARGET_OS_IPHONE 201 testdigestandsign(privKey, pubKey); 202#endif 203 204 const void *privkeys[] = { 205 kSecValueRef 206 }; 207 const void *privvalues[] = { 208 privKey 209 }; 210 CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues, 211 sizeof(privkeys) / sizeof(*privkeys), NULL, NULL); 212#if TARGET_OS_IPHONE 213 ok_status(SecItemAdd(privitem, NULL), "add private key"); 214#endif 215 ok_status(SecItemDelete(privitem), "delete private key"); 216 CFReleaseNull(privitem); 217 218 const void *pubkeys[] = { 219 kSecValueRef 220 }; 221 const void *pubvalues[] = { 222 pubKey 223 }; 224 CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues, 225 sizeof(pubkeys) / sizeof(*pubkeys), NULL, NULL); 226#if TARGET_OS_IPHONE 227 ok_status(SecItemAdd(pubitem, NULL), "add public key"); 228#endif 229 ok_status(SecItemDelete(pubitem), "delete public key"); 230 CFReleaseNull(pubitem); 231 232 /* Cleanup. */ 233 CFReleaseNull(pubKey); 234 CFReleaseNull(privKey); 235} 236} 237 238 239static void testkeygen2(size_t keySizeInBits) { 240 SecKeyRef pubKey = NULL, privKey = NULL; 241 size_t keySizeInBytes = (keySizeInBits + 7) / 8; 242 CFNumberRef kzib; 243 244 CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault); 245 CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID); 246 CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); 247 CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); 248 249 CFReleaseNull(ourUUID); 250 CFReleaseNull(uuidString); 251 252 CFStringAppend(publicName, CFSTR("-Public-41")); 253 CFStringAppend(privateName, CFSTR("-Private-41")); 254 255 CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 256 CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 257 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName); 258 CFDictionaryAddValue(privd, kSecAttrLabel, privateName); 259 260 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits); 261 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 262 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC); 263 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); 264 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue); 265 CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd); 266 CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd); 267 268 OSStatus status; 269 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), 270 "Generate %ld bit (%ld byte) persistent RSA keypair", 271 keySizeInBits, keySizeInBytes); 272 CFRelease(kzib); 273 CFRelease(kgp); 274 275SKIP: { 276 skip("keygen failed", 8, status == errSecSuccess); 277 ok(pubKey, "pubkey returned"); 278 ok(privKey, "privKey returned"); 279 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); 280 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); 281 282 SecKeyRef pubKey2, privKey2; 283 CFDictionaryAddValue(pubd, kSecClass, kSecClassKey); 284 CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue); 285 CFDictionaryAddValue(privd, kSecClass, kSecClassKey); 286 CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue); 287 CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue); 288 ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2), 289 "retrieve pub key by label"); 290 ok(pubKey2, "got valid object"); 291 ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2), 292 "retrieve priv key by label and kSecAttrCanSign"); 293 ok(privKey2, "got valid object"); 294 295 /* Sign something. */ 296 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; 297 size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize); 298 uint8_t sig[sigLen]; 299 ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1, 300 something, sizeof(something), sig, &sigLen), "sign something"); 301 ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1, 302 something, sizeof(something), sig, sigLen), "verify sig on something"); 303 304 /* Cleanup. */ 305 CFReleaseNull(pubKey2); 306 CFReleaseNull(privKey2); 307} 308 309 /* delete from keychain - note: do it before releasing publicName and privateName 310 because pubd and privd have no retain/release callbacks */ 311 ok_status(SecItemDelete(pubd), "delete generated pub key"); 312 ok_status(SecItemDelete(privd), "delete generated priv key"); 313 314 /* Cleanup. */ 315 CFReleaseNull(pubKey); 316 CFReleaseNull(privKey); 317 318 CFReleaseNull(publicName); 319 CFReleaseNull(privateName); 320 321 CFRelease(pubd); 322 CFRelease(privd); 323} 324 325 326/* Test basic add delete update copy matching stuff. */ 327static void tests(void) 328{ 329 testkeygen(192); 330#if TARGET_OS_IPHONE 331 testkeygen(224); 332#endif 333 testkeygen(256); 334 testkeygen(384); 335 testkeygen(521); 336 337 testkeygen2(192); 338#if TARGET_OS_IPHONE 339 testkeygen2(224); 340#endif 341 testkeygen2(256); 342 testkeygen2(384); 343 testkeygen2(521); 344 345} 346 347int kc_41_sececkey(int argc, char *const *argv) 348{ 349#if TARGET_OS_IPHONE 350 plan_tests(140); 351#else 352 plan_tests(88); 353#endif 354 355 tests(); 356 357 return 0; 358} 359