1// 2// si-41-sececkey.c 3// regressions 4// 5// Created by Mitch Adler on 5/20/11. 6// Copyright 2011 Apple Inc. All rights reserved. 7// 8 9/* 10 * si-40-seckey.c 11 * Security 12 * 13 * Created by Michael Brouwer on 1/29/07. 14 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved. 15 * 16 */ 17 18#include <CoreFoundation/CoreFoundation.h> 19#include <Security/SecCertificate.h> 20#include <Security/SecCertificateInternal.h> 21#include <Security/SecKey.h> 22#include <Security/SecKeyPriv.h> 23#include <Security/SecItem.h> 24#include <Security/SecAsn1Types.h> 25#include <Security/oidsalg.h> 26#include <Security/SecureTransport.h> 27#include <Security/SecRandom.h> 28#include <utilities/array_size.h> 29#include <CommonCrypto/CommonDigest.h> 30#include <libDER/libDER.h> 31#include <stdlib.h> 32#include <unistd.h> 33 34#include "Security_regressions.h" 35 36#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); if (_cf) { (CF) = NULL; CFRelease(_cf); } } 37 38 39static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) { 40 uint8_t dataToDigest[256] = {0,}; 41 size_t dataToDigestLen = sizeof(dataToDigest); 42 size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize); 43 uint8_t sig[sigLen]; 44 45 DERItem oid; 46 oid.length = algId->algorithm.Length; 47 oid.data = algId->algorithm.Data; 48 49 /* Get the oid in decimal for display purposes. */ 50 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid); 51 char oidBuf[40]; 52 CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8); 53 CFRelease(oidStr); 54 55SKIP: { 56 OSStatus status; 57 58 /* Time to sign. */ 59 ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen, 60 sig, &sigLen), 61 "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8); 62 63 skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess); 64 65 /* Verify the signature we just made. */ 66 ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 67 sig, sigLen), "digest and verify"); 68 /* Invalidate the signature. */ 69 sig[0] ^= 0xff; 70 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 71 sig, sigLen), errSSLCrypto, "digest and verify bad sig"); 72 sig[0] ^= 0xff; 73 dataToDigest[0] ^= 0xff; 74 is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, 75 sig, sigLen), errSSLCrypto, "digest and verify bad digest"); 76} 77} 78 79static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) { 80 static const SecAsn1Oid *oids[] = { 81 &CSSMOID_ECDSA_WithSHA1, 82#if 0 83 &CSSMOID_ECDSA_WithSHA224, 84 &CSSMOID_ECDSA_WithSHA256, 85 &CSSMOID_ECDSA_WithSHA384, 86 &CSSMOID_ECDSA_WithSHA512, 87#endif 88 }; 89 90 uint32_t ix; 91 SecAsn1AlgId algId = {}; 92 for (ix = 0; ix < array_size(oids); ++ix) { 93 if (oids[ix]) { 94 algId.algorithm = *oids[ix]; 95 } else { 96 algId.algorithm.Length = 0; 97 algId.algorithm.Data = NULL; 98 } 99 100 testdigestandsignalg(privKey, pubKey, &algId); 101 } 102} 103 104static void testkeygen(size_t keySizeInBits) { 105 SecKeyRef pubKey = NULL, privKey = NULL; 106 size_t keySizeInBytes = (keySizeInBits + 7) / 8; 107 CFNumberRef kzib; 108 int32_t keysz32 = (int32_t)keySizeInBits; 109 110 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32); 111 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 112 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC); 113 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); 114 115 OSStatus status; 116 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), 117 "Generate %ld bit (%ld byte) EC keypair", keySizeInBits, 118 keySizeInBytes); 119 CFRelease(kzib); 120 CFRelease(kgp); 121 122SKIP: { 123 skip("keygen failed", 8, status == errSecSuccess); 124 ok(pubKey, "pubkey returned"); 125 ok(privKey, "privKey returned"); 126 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); 127 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); 128 129 /* Sign something. */ 130 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; 131 uint8_t sig[8+2*keySizeInBytes]; 132 size_t sigLen = sizeof(sig); 133 ok_status(SecKeyRawSign(privKey, kSecPaddingNone, 134 something, sizeof(something), sig, &sigLen), "sign something"); 135 ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone, 136 something, sizeof(something), sig, sigLen), "verify sig on something"); 137 138 testdigestandsign(privKey, pubKey); 139 140 const void *privkeys[] = { 141 kSecValueRef 142 }; 143 const void *privvalues[] = { 144 privKey 145 }; 146 CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues, 147 array_size(privkeys), NULL, NULL); 148 ok_status(SecItemAdd(privitem, NULL), "add private key"); 149 ok_status(SecItemDelete(privitem), "delete public key"); 150 CFReleaseNull(privitem); 151 152 const void *pubkeys[] = { 153 kSecValueRef 154 }; 155 const void *pubvalues[] = { 156 pubKey 157 }; 158 CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues, 159 array_size(pubkeys), NULL, NULL); 160 ok_status(SecItemAdd(pubitem, NULL), "add public key"); 161 ok_status(SecItemDelete(pubitem), "delete public key"); 162 CFReleaseNull(pubitem); 163 164 /* Cleanup. */ 165 CFReleaseNull(pubKey); 166 CFReleaseNull(privKey); 167} 168} 169 170 171static void testkeygen2(size_t keySizeInBits) { 172 SecKeyRef pubKey = NULL, privKey = NULL; 173 size_t keySizeInBytes = (keySizeInBits + 7) / 8; 174 CFNumberRef kzib; 175 int32_t keysz32 = (int32_t)keySizeInBits; 176 177 CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault); 178 CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID); 179 CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); 180 CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); 181 182 CFReleaseNull(ourUUID); 183 CFReleaseNull(uuidString); 184 185 CFStringAppend(publicName, CFSTR("-Public-41")); 186 CFStringAppend(privateName, CFSTR("-Private-41")); 187 188 CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 189 CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 190 CFDictionaryAddValue(pubd, kSecAttrLabel, publicName); 191 CFDictionaryAddValue(privd, kSecAttrLabel, privateName); 192 193 kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32); 194 CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 195 CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC); 196 CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); 197 CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue); 198 CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd); 199 CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd); 200 201 OSStatus status; 202 ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), 203 "Generate %ld bit (%ld byte) persistent RSA keypair", 204 keySizeInBits, keySizeInBytes); 205 CFRelease(kzib); 206 CFRelease(kgp); 207 208SKIP: { 209 skip("keygen failed", 8, status == errSecSuccess); 210 ok(pubKey, "pubkey returned"); 211 ok(privKey, "privKey returned"); 212 is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); 213 is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); 214 215 SecKeyRef pubKey2, privKey2; 216 CFDictionaryAddValue(pubd, kSecClass, kSecClassKey); 217 CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue); 218 CFDictionaryAddValue(privd, kSecClass, kSecClassKey); 219 CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue); 220 CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue); 221 ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2), 222 "retrieve pub key by label"); 223 ok(pubKey2, "got valid object"); 224 ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2), 225 "retrieve priv key by label and kSecAttrCanSign"); 226 ok(privKey2, "got valid object"); 227 228 /* Sign something. */ 229 uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; 230 size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize); 231 uint8_t sig[sigLen]; 232 ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1, 233 something, sizeof(something), sig, &sigLen), "sign something"); 234 ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1, 235 something, sizeof(something), sig, sigLen), "verify sig on something"); 236 237 /* Cleanup. */ 238 CFReleaseNull(pubKey2); 239 CFReleaseNull(privKey2); 240} 241 242 /* delete from keychain - note: do it before releasing publicName and privateName 243 because pubd and privd have no retain/release callbacks */ 244 ok_status(SecItemDelete(pubd), "delete generated pub key"); 245 ok_status(SecItemDelete(privd), "delete generated priv key"); 246 247 /* Cleanup. */ 248 CFReleaseNull(pubKey); 249 CFReleaseNull(privKey); 250 251 CFReleaseNull(publicName); 252 CFReleaseNull(privateName); 253 254 CFRelease(pubd); 255 CFRelease(privd); 256} 257 258 259/* Test basic add delete update copy matching stuff. */ 260static void tests(void) 261{ 262 testkeygen(192); 263 testkeygen(224); 264 testkeygen(256); 265 testkeygen(384); 266 testkeygen(521); 267 268 testkeygen2(192); 269 testkeygen2(224); 270 testkeygen2(256); 271 testkeygen2(384); 272 testkeygen2(521); 273 274} 275 276int si_41_sececkey(int argc, char *const *argv) 277{ 278 plan_tests(140); 279 280 tests(); 281 282 return 0; 283} 284