X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/sec/Security/SecRSAKey.c diff --git a/sec/Security/SecRSAKey.c b/sec/Security/SecRSAKey.c deleted file mode 100644 index 51bb5207..00000000 --- a/sec/Security/SecRSAKey.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * Copyright (c) 2006-2010 Apple 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@ - */ - -/* - * SecRSAKey.c - CoreFoundation based rsa key object - */ - - -#include "SecRSAKey.h" -#include "SecRSAKeyPriv.h" -#include -#include -#include -#include -#include /* For error codes. */ -#include /* For error codes. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecItemPriv.h" -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include -#include - -#define kMaximumRSAKeyBits 4096 -#define kMaximumRSAKeyBytes ccn_sizeof(kMaximumRSAKeyBits) - -#define RSA_PKCS1_PAD_SIGN 0x01 -#define RSA_PKCS1_PAD_ENCRYPT 0x02 - -static void ccn_c_dump(cc_size count, const cc_unit *s) -{ - printf("{ "); - cc_size ix; - for (ix = count; ix--;) { - printf("0x%.02x, 0x%.02x, 0x%.02x, 0x%.02x, ", - (int) ((s[ix] >> 24) & 0xFF), - (int) ((s[ix] >> 16) & 0xFF), - (int) ((s[ix] >> 8 ) & 0xFF), - (int) ((s[ix] >> 0 ) & 0xFF)); - } - printf("};"); -} - -static void ccn_cprint(cc_size count, char* prefix, const cc_unit *s) -{ - printf("%s", prefix); - ccn_c_dump(count, s); - printf("\n"); -} - -void ccrsa_dump_full_key(ccrsa_full_ctx_t key); // Suppress warnings -void ccrsa_dump_full_key(ccrsa_full_ctx_t key) { - ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); - ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); - ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); - ccn_cprint(ccrsa_ctx_n(key), "uint8_t d[] = ", ccrsa_ctx_d(key)); - - printf("cc_size np = %lu;\n", cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t p[] = ", - cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))) + 1, "uint8_t rp[] = ", - cczp_recip(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); - printf("cc_size nq = %lu;\n", cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t q[] = ", - cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))) + 1, "uint8_t rq[] = ", - cczp_recip(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t dp[] = ", - ccrsa_ctx_private_dp(ccrsa_ctx_private(key))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t dq[] = ", - ccrsa_ctx_private_dq(ccrsa_ctx_private(key))); - ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t qinv[] = ", - ccrsa_ctx_private_qinv(ccrsa_ctx_private(key))); - printf("--\n"); -} - -void ccrsa_dump_public_key(ccrsa_pub_ctx_t key); // Suppress warning. -void ccrsa_dump_public_key(ccrsa_pub_ctx_t key) { - ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); - ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); - ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); - - printf("--\n"); -} - -/* - * - * Public Key - * - */ - -/* Public key static functions. */ -static void SecRSAPublicKeyDestroy(SecKeyRef key) { - /* Zero out the public key */ - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - cc_zero(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey.pub); -} - -#define cc_skip_zeros(size, ptr) { while (size > 0 && *ptr == 0) { ++ptr; --size; } } - -// -// pubkey is initilaized with an n which is the maximum it can hold -// We set the n to its correct value given m. -// -static int ccrsa_pub_init(ccrsa_pub_ctx_t pubkey, - size_t m_size, const uint8_t* m, - size_t e_size, const uint8_t* e) -{ - cc_skip_zeros(m_size, m); - - cc_size nm = ccn_nof_size(m_size); - if (nm > ccrsa_ctx_n(pubkey)) - return -1; - - ccrsa_ctx_n(pubkey) = nm; - - ccn_read_uint(nm, ccrsa_ctx_m(pubkey), m_size, m); - cczp_init(ccrsa_ctx_zm(pubkey)); - - return ccn_read_uint(nm, ccrsa_ctx_e(pubkey), e_size, e); -} - - -static OSStatus ccrsa_pub_decode(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) -{ - OSStatus result = errSecParam; - - DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; - DERRSAPubKeyPKCS1 decodedKey; - - require_noerr_action(DERParseSequence(&keyItem, - DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs, - &decodedKey, sizeof(decodedKey)), - errOut, result = errSecDecode); - - require_noerr(ccrsa_pub_init(pubkey, - decodedKey.modulus.length, decodedKey.modulus.data, - decodedKey.pubExponent.length, decodedKey.pubExponent.data), - errOut); - - result = errSecSuccess; - -errOut: - return result; -} - -static OSStatus ccrsa_pub_decode_apple(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) -{ - OSStatus result = errSecParam; - - DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; - DERRSAPubKeyApple decodedKey; - - require_noerr_action(DERParseSequence(&keyItem, - DERNumRSAPubKeyAppleItemSpecs, DERRSAPubKeyAppleItemSpecs, - &decodedKey, sizeof(decodedKey)), - errOut, result = errSecDecode); - - // We could honor the recipricol, but we don't think this is used enough to care. - // Don't bother exploding the below function to try to handle this case, it computes. - - require_noerr(ccrsa_pub_init(pubkey, - decodedKey.modulus.length, decodedKey.modulus.data, - decodedKey.pubExponent.length, decodedKey.pubExponent.data), - errOut); - - result = errSecSuccess; - -errOut: - return result; -} - - -static void ccasn_encode_int(cc_size n, const cc_unit*s, size_t s_size, uint8_t **buffer) -{ - **buffer = ASN1_INTEGER; - *buffer += 1; - - DERSize itemLength = 4; - DEREncodeLength(s_size, *buffer, &itemLength); - *buffer += itemLength; - - ccn_write_int(n, s, s_size, *buffer); - - *buffer += s_size; -} - - -static OSStatus SecRSAPublicKeyInit(SecKeyRef key, - const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { - - OSStatus result = errSecParam; - - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - // Set maximum size for parsers - ccrsa_ctx_n(pubkey) = ccn_nof(kMaximumRSAKeyBits); - - switch (encoding) { - case kSecKeyEncodingBytes: // Octets is PKCS1 - case kSecKeyEncodingPkcs1: - result = ccrsa_pub_decode(pubkey, keyDataLength, keyData); - break; - case kSecKeyEncodingApplePkcs1: - result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); - break; - case kSecKeyEncodingRSAPublicParams: - { - SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; - - require_noerr(ccrsa_pub_init(pubkey, - params->modulusLength, params->modulus, - params->exponentLength, params->exponent), errOut); - - result = errSecSuccess; - break; - } - case kSecExtractPublicFromPrivate: - { - ccrsa_full_ctx_t fullKey; - fullKey.full = (ccrsa_full_ctx*) keyData; - - cc_size fullKeyN = ccrsa_ctx_n(fullKey); - require(fullKeyN <= ccrsa_ctx_n(pubkey), errOut); - memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(fullKeyN))); - result = errSecSuccess; - break; - } - default: - break; - } - -errOut: - return result; -} - -static OSStatus SecRSAPublicKeyRawVerify(SecKeyRef key, SecPadding padding, - const uint8_t *signedData, size_t signedDataLen, - const uint8_t *sig, size_t sigLen) { - OSStatus result = errSSLCrypto; - - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - cc_unit s[ccrsa_ctx_n(pubkey)]; - - ccn_read_uint(ccrsa_ctx_n(pubkey), s, sigLen, sig); - ccrsa_pub_crypt(pubkey, s, s); - ccn_swap(ccrsa_ctx_n(pubkey), s); - - const uint8_t* sBytes = (uint8_t*) s; - const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); - - switch (padding) { - case kSecPaddingNone: - // Skip leading zeros as long as s is bigger than signedData. - while (((ptrdiff_t)signedDataLen < (sEnd - sBytes)) && (*sBytes == 0)) - ++sBytes; - break; - - case kSecPaddingPKCS1: - { - // Verify and skip PKCS1 padding: - // - // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData - // - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; - - while (prefix_zeros--) - require_quiet(*sBytes++ == 0x00, errOut); - - require_quiet(*sBytes++ == 0x00, errOut); - require_quiet(*sBytes++ == RSA_PKCS1_PAD_SIGN, errOut); - - while (*sBytes == 0xFF) { - require_quiet(++sBytes < sEnd, errOut); - } - // Required to have at least 8 0xFFs - require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); - - require_quiet(*sBytes == 0x00, errOut); - require_quiet(++sBytes < sEnd, errOut); - break; - } - case kSecPaddingOAEP: - result = errSecParam; - goto errOut; - - default: - result = errSecUnimplemented; - goto errOut; - } - - // Compare the rest. - require_quiet((sEnd - sBytes) == (ptrdiff_t)signedDataLen, errOut); - require_quiet(memcmp(sBytes, signedData, signedDataLen) == 0, errOut); - - result = errSecSuccess; - -errOut: - cc_zero(ccrsa_ctx_n(pubkey), s); - - return result; -} - -static OSStatus SecRSAPublicKeyRawEncrypt(SecKeyRef key, SecPadding padding, - const uint8_t *plainText, size_t plainTextLen, - uint8_t *cipherText, size_t *cipherTextLen) { - OSStatus result = errSecParam; - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - cc_unit s[ccrsa_ctx_n(pubkey)]; - const size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - - require(cipherTextLen, errOut); - require(*cipherTextLen >= m_size, errOut); - - uint8_t* sBytes = (uint8_t*) s; - - switch (padding) { - case kSecPaddingNone: - // We'll allow modulus size assuming input is smaller than modulus - require_quiet(plainTextLen <= m_size, errOut); - require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(pubkey), s, plainTextLen, plainText), errOut); - require_quiet(ccn_cmp(ccrsa_ctx_n(pubkey), s, ccrsa_ctx_m(pubkey)) < 0, errOut); - break; - - case kSecPaddingPKCS1: - { - // Create PKCS1 padding: - // - // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData - // - const int kMinimumPadding = 1 + 1 + 8 + 1; - - require_quiet(plainTextLen <= m_size - kMinimumPadding, errOut); - - size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; - - while (prefix_zeros--) - *sBytes++ = 0x00; - - size_t pad_size = m_size - plainTextLen; - - *sBytes++ = 0x00; - *sBytes++ = RSA_PKCS1_PAD_ENCRYPT; - - ccrng_generate(ccrng_seckey, pad_size - 3, sBytes); - // Remove zeroes from the random pad - - const uint8_t* sEndOfPad = sBytes + (pad_size - 3); - while (sBytes < sEndOfPad) - { - if (*sBytes == 0x00) - *sBytes = 0xFF; // Michael said 0xFF was good enough. - - ++sBytes; - } - - *sBytes++ = 0x00; - - memcpy(sBytes, plainText, plainTextLen); - - ccn_swap(ccrsa_ctx_n(pubkey), s); - break; - } - case kSecPaddingOAEP: - { - const struct ccdigest_info* di = ccsha1_di(); - - const size_t encodingOverhead = 2 + 2 * di->output_size; - - require_action(m_size > encodingOverhead, errOut, result = errSecParam); - require_action_quiet(plainTextLen <= m_size - encodingOverhead, errOut, result = errSecParam); - - require_noerr_action(ccrsa_oaep_encode(di, - ccrng_seckey, - m_size, s, - plainTextLen, plainText), errOut, result = errSecInternal); - break; - } - default: - goto errOut; - } - - - ccrsa_pub_crypt(pubkey, s, s); - - ccn_write_uint_padded(ccrsa_ctx_n(pubkey), s, m_size, cipherText); - *cipherTextLen = m_size; - - result = errSecSuccess; - -errOut: - ccn_zero(ccrsa_ctx_n(pubkey), s); - return result; -} - -static OSStatus SecRSAPublicKeyRawDecrypt(SecKeyRef key, SecPadding padding, - const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { - OSStatus result = errSSLCrypto; - - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - cc_unit s[ccrsa_ctx_n(pubkey)]; - - require_action_quiet(cipherText != NULL, errOut, result = errSecParam); - require_action_quiet(plainText != NULL, errOut, result = errSecParam); - require_action_quiet(plainTextLen != NULL, errOut, result = errSecParam); - - ccn_read_uint(ccrsa_ctx_n(pubkey), s, cipherTextLen, cipherText); - ccrsa_pub_crypt(pubkey, s, s); - ccn_swap(ccrsa_ctx_n(pubkey), s); - - const uint8_t* sBytes = (uint8_t*) s; - const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); - - switch (padding) { - case kSecPaddingNone: - // Skip leading zeros - // We return the bytes for a number and - // trim leading zeroes - while (sBytes < sEnd && *sBytes == 0x00) - ++sBytes; - break; - - case kSecPaddingPKCS1: - { - // Verify and skip PKCS1 padding: - // - // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData - // - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; - - while (prefix_zeros--) - require_quiet(*sBytes++ == 0x00, errOut); - - require_quiet(*sBytes++ == 0x00, errOut); - require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); - - while (*sBytes != 0x00) { - require_quiet(++sBytes < sEnd, errOut); - } - // Required to have at least 8 0xFFs - require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); - - require_quiet(*sBytes == 0x00, errOut); - require_quiet(++sBytes < sEnd, errOut); - - break; - } - case kSecPaddingOAEP: - result = errSecParam; - default: - goto errOut; - } - - // Return the rest. - require_action((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut, result = errSecParam); - - *plainTextLen = sEnd - sBytes; - memcpy(plainText, sBytes, *plainTextLen); - - result = errSecSuccess; - -errOut: - ccn_zero(ccrsa_ctx_n(pubkey), s); - - return result; -} - -static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - return ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); -} - - -static CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ctx_t pubkey) -{ - size_t m_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - size_t e_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); - - const size_t seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + - DERLengthOfItem(ASN1_INTEGER, e_size); - - const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); - - CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); - - if (pkcs1 == NULL) - return NULL; - - CFDataSetLength(pkcs1, result_size); - - uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); - - *bytes++ = ASN1_CONSTR_SEQUENCE; - - DERSize itemLength = 4; - DEREncodeLength(seq_size, bytes, &itemLength); - bytes += itemLength; - - ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, &bytes); - ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, &bytes); - - return pkcs1; -} - -static OSStatus SecRSAPublicKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) -{ - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - CFAllocatorRef allocator = CFGetAllocator(key); - *serialized = SecRSAPublicKeyCreatePKCS1(allocator, pubkey); - - if (NULL == *serialized) - return errSecDecode; - else - return errSecSuccess; -} - -static CFDictionaryRef SecRSAPublicKeyCopyAttributeDictionary(SecKeyRef key) { - return SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeRSA); -} - -static CFStringRef SecRSAPublicKeyCopyDescription(SecKeyRef key) { - - CFStringRef keyDescription = NULL; - CFDataRef modRef = SecKeyCopyModulus(key); - - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - CFStringRef modulusString = CFDataCopyHexString(modRef); - require( modulusString, fail); - - keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( ""), SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), (long long)*ccrsa_ctx_e(pubkey), (long long)*ccrsa_ctx_e(pubkey), modulusString, key); - -fail: - CFReleaseSafe(modRef); - CFReleaseSafe(modulusString); - if(!keyDescription) - keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR(""), (long)SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); - - return keyDescription; -} - -SecKeyDescriptor kSecRSAPublicKeyDescriptor = { - kSecKeyDescriptorVersion, - "RSAPublicKey", - ccrsa_pub_ctx_size(kMaximumRSAKeyBytes), /* extraBytes */ - SecRSAPublicKeyInit, - SecRSAPublicKeyDestroy, - NULL, /* SecKeyRawSignMethod */ - SecRSAPublicKeyRawVerify, - SecRSAPublicKeyRawEncrypt, - SecRSAPublicKeyRawDecrypt, - NULL, /* SecKeyComputeMethod */ - SecRSAPublicKeyBlockSize, - SecRSAPublicKeyCopyAttributeDictionary, - SecRSAPublicKeyCopyDescription, - NULL, - SecRSAPublicKeyCopyPublicSerialization, -}; - -/* Public Key API functions. */ -SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, - const uint8_t *keyData, CFIndex keyDataLength, - SecKeyEncoding encoding) { - return SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, keyData, - keyDataLength, encoding); -} - -CFDataRef SecKeyCopyModulus(SecKeyRef key) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - - CFAllocatorRef allocator = CFGetAllocator(key); - CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); - - if (modulusData == NULL) - return NULL; - - CFDataSetLength(modulusData, m_size); - - ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); - - return modulusData; -} - -CFDataRef SecKeyCopyExponent(SecKeyRef key) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); - - CFAllocatorRef allocator = CFGetAllocator(key); - CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); - - if (exponentData == NULL) - return NULL; - - CFDataSetLength(exponentData, e_size); - - ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); - - return exponentData; -} - - -/* - * - * Private Key - * - */ - -/* Private key static functions. */ -static void SecRSAPrivateKeyDestroy(SecKeyRef key) { - /* Zero out the public key */ - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - cc_zero(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); -} - -static int ccrsa_priv_init(ccrsa_priv_ctx_t privkey, - size_t p_size, const uint8_t* p, - size_t q_size, const uint8_t* q, - size_t dp_size, const uint8_t* dp, - size_t dq_size, const uint8_t* dq, - size_t qinv_size, const uint8_t* qinv) -{ - int result = -1; - - const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); - cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); - - if (ccn_read_uint(np, CCZP_PRIME(ccrsa_ctx_private_zp(privkey)), p_size, p)) - goto errOut; - cczp_init(ccrsa_ctx_private_zp(privkey)); - if (ccn_read_uint(np, ccrsa_ctx_private_dp(privkey), dp_size, dp)) - goto errOut; - if (ccn_read_uint(np, ccrsa_ctx_private_qinv(privkey), qinv_size, qinv)) - goto errOut; - - if (ccn_read_uint(nq, CCZP_PRIME(ccrsa_ctx_private_zq(privkey)), q_size, q)) - goto errOut; - - nq = ccn_n(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); - CCZP_N(ccrsa_ctx_private_zq(privkey)) = nq; - - cczp_init(ccrsa_ctx_private_zq(privkey)); - if (ccn_read_uint(nq, ccrsa_ctx_private_dq(privkey), dq_size, dq)) - goto errOut; - - result = 0; - -errOut: - return result; -} - - -static OSStatus ccrsa_full_decode(ccrsa_full_ctx_t fullkey, size_t pkcs1_size, const uint8_t* pkcs1) -{ - OSStatus result = errSecParam; - - DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; - DERRSAKeyPair decodedKey; - - require_noerr_action(DERParseSequence(&keyItem, - DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs, - &decodedKey, sizeof(decodedKey)), - errOut, result = errSecDecode); - - require_noerr(ccrsa_pub_init(fullkey, - decodedKey.n.length, decodedKey.n.data, - decodedKey.e.length, decodedKey.e.data), - errOut); - ccn_read_uint(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), - decodedKey.d.length, decodedKey.d.data); - { - ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); - CCZP_N(ccrsa_ctx_private_zp(privkey)) = ccn_nof((ccn_bitsof_n(ccrsa_ctx_n(fullkey)) / 2) + 1); - CCZP_N(ccrsa_ctx_private_zq(privkey)) = cczp_n(ccrsa_ctx_private_zp(privkey)); - - // TODO: Actually remember decodedKey.d. - - require_noerr(ccrsa_priv_init(privkey, - decodedKey.p.length, decodedKey.p.data, - decodedKey.q.length, decodedKey.q.data, - decodedKey.dp.length, decodedKey.dp.data, - decodedKey.dq.length, decodedKey.dq.data, - decodedKey.qInv.length, decodedKey.qInv.data), - errOut); - } - - result = errSecSuccess; - -errOut: - return result; -} - -static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, - const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { - OSStatus result = errSecParam; - - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - // Set maximum size for parsers - ccrsa_ctx_n(fullkey) = ccn_nof(kMaximumRSAKeyBits); - - switch (encoding) { - case kSecKeyEncodingBytes: // Octets is PKCS1 - case kSecKeyEncodingPkcs1: - result = ccrsa_full_decode(fullkey, keyDataLength, keyData); - break; - case kSecGenerateKey: - { - CFDictionaryRef parameters = (CFDictionaryRef) keyData; - - CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); - CFIndex keyLengthInBits = getIntValue(ksize); - - if (keyLengthInBits < 256 || keyLengthInBits > kMaximumRSAKeyBits) { - secwarning("Invalid or missing key size in: %@", parameters); - return errSecKeySizeNotAllowed; - } - - /* TODO: Add support for kSecPublicExponent parameter. */ - static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 - if (!ccrsa_generate_key(keyLengthInBits, fullkey.full, sizeof(e), e, ccrng_seckey)) - result = errSecSuccess; - break; - } - default: - break; - } - - return result; -} - -static OSStatus SecRSAPrivateKeyRawSign(SecKeyRef key, SecPadding padding, - const uint8_t *dataToSign, size_t dataToSignLen, - uint8_t *sig, size_t *sigLen) { - - OSStatus result = errSecParam; - - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); - cc_unit s[ccrsa_ctx_n(fullkey)]; - - uint8_t* sBytes = (uint8_t*) s; - - require(sigLen, errOut); - require(*sigLen >= m_size, errOut); - - switch (padding) { - case kSecPaddingNone: - // We'll allow modulus size assuming input is smaller than modulus - require_quiet(dataToSignLen <= m_size, errOut); - require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(fullkey), s, dataToSignLen, dataToSign), errOut); - require_quiet(ccn_cmp(ccrsa_ctx_n(fullkey), s, ccrsa_ctx_m(fullkey)) < 0, errOut); - break; - - case kSecPaddingPKCS1: - { - // Create PKCS1 padding: - // - // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData - // - const int kMinimumPadding = 1 + 1 + 8 + 1; - - require_quiet(dataToSignLen <= m_size - kMinimumPadding, errOut); - - size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; - - while (prefix_zeros--) - *sBytes++ = 0x00; - - size_t pad_size = m_size - dataToSignLen; - - *sBytes++ = 0x00; - *sBytes++ = RSA_PKCS1_PAD_SIGN; - - size_t ff_size; - for(ff_size = pad_size - 3; ff_size > 0; --ff_size) - *sBytes++ = 0xFF; - - *sBytes++ = 0x00; - - // Get the user data into s looking like a ccn. - memcpy(sBytes, dataToSign, dataToSignLen); - ccn_swap(ccrsa_ctx_n(fullkey), s); - - break; - } - case kSecPaddingOAEP: - result = errSecParam; - default: - goto errOut; - } - - ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); - - // Pad with leading zeros to fit in modulus size - ccn_write_uint_padded(ccrsa_ctx_n(fullkey), s, m_size, sig); - *sigLen = m_size; - - result = errSecSuccess; - -errOut: - ccn_zero(ccrsa_ctx_n(fullkey), s); - return result; -} - -static OSStatus SecRSAPrivateKeyRawDecrypt(SecKeyRef key, SecPadding padding, - const uint8_t *cipherText, size_t cipherTextLen, - uint8_t *plainText, size_t *plainTextLen) { - OSStatus result = errSSLCrypto; - - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); - - cc_unit s[ccrsa_ctx_n(fullkey)]; - uint8_t recoveredData[ccn_sizeof_n(ccrsa_ctx_n(fullkey))]; - - ccn_read_uint(ccrsa_ctx_n(fullkey), s, cipherTextLen, cipherText); - ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); - - const uint8_t* sBytes = (uint8_t*) s; - const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(fullkey)); - - require(plainTextLen, errOut); - - switch (padding) { - case kSecPaddingNone: - ccn_swap(ccrsa_ctx_n(fullkey), s); - // Skip Zeros since our contract is to do so. - while (sBytes < sEnd && *sBytes == 0x00) - ++sBytes; - break; - - case kSecPaddingPKCS1: - { - ccn_swap(ccrsa_ctx_n(fullkey), s); - // Verify and skip PKCS1 padding: - // - // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData - // - - size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; - - while (prefix_zeros--) - require_quiet(*sBytes++ == 0x00, errOut); - - require_quiet(*sBytes++ == 0x00, errOut); - require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); - - while (*sBytes != 0x00) { - require_quiet(++sBytes < sEnd, errOut); - } - // Required to have at least 8 non-zeros - require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); - - require_quiet(*sBytes == 0x00, errOut); - require_quiet(++sBytes < sEnd, errOut); - break; - } - case kSecPaddingOAEP: - { - size_t length = sizeof(recoveredData); - - require_noerr_quiet(ccrsa_oaep_decode(ccsha1_di(), - &length, recoveredData, - ccn_write_uint_size(ccrsa_ctx_n(fullkey),ccrsa_ctx_m(fullkey)), s - ), errOut); - - sBytes = recoveredData; - sEnd = recoveredData + length; - break; - } - default: - goto errOut; - } - - require((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut); - *plainTextLen = sEnd - sBytes; - memcpy(plainText, sBytes, *plainTextLen); - - result = errSecSuccess; - -errOut: - bzero(recoveredData, sizeof(recoveredData)); - ccn_zero(ccrsa_ctx_n(fullkey), s); - - return result; -} - -static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); -} - -static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey) -{ - ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); - - const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); - const cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); - - size_t m_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); - size_t e_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey)); - size_t d_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey)); - - size_t p_size = ccn_write_int_size(np, cczp_prime(ccrsa_ctx_private_zp(privkey))); - size_t q_size = ccn_write_int_size(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); - - size_t dp_size = ccn_write_int_size(np, ccrsa_ctx_private_dp(privkey)); - size_t dq_size = ccn_write_int_size(nq, ccrsa_ctx_private_dq(privkey)); - - size_t qinv_size = ccn_write_int_size(np, ccrsa_ctx_private_qinv(privkey)); - - const size_t seq_size = 3 + - DERLengthOfItem(ASN1_INTEGER, m_size) + - DERLengthOfItem(ASN1_INTEGER, e_size) + - DERLengthOfItem(ASN1_INTEGER, d_size) + - DERLengthOfItem(ASN1_INTEGER, p_size) + - DERLengthOfItem(ASN1_INTEGER, q_size) + - DERLengthOfItem(ASN1_INTEGER, dp_size) + - DERLengthOfItem(ASN1_INTEGER, dq_size) + - DERLengthOfItem(ASN1_INTEGER, qinv_size); - - const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); - - CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); - - if (pkcs1 == NULL) - return NULL; - - CFDataSetLength(pkcs1, result_size); - - uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); - - *bytes++ = ASN1_CONSTR_SEQUENCE; - - DERSize itemLength = 4; - DEREncodeLength(seq_size, bytes, &itemLength); - bytes += itemLength; - - *bytes++ = ASN1_INTEGER; - *bytes++ = 0x01; - *bytes++ = 0x00; - - ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey), m_size, &bytes); - ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey), e_size, &bytes); - ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), d_size, &bytes); - - ccasn_encode_int(np, cczp_prime(ccrsa_ctx_private_zp(privkey)), p_size, &bytes); - ccasn_encode_int(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)), q_size, &bytes); - ccasn_encode_int(np, ccrsa_ctx_private_dp(privkey), dp_size, &bytes); - ccasn_encode_int(nq, ccrsa_ctx_private_dq(privkey), dq_size, &bytes); - ccasn_encode_int(np, ccrsa_ctx_private_qinv(privkey), qinv_size, &bytes); - - return pkcs1; -} - -static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) -{ - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - CFAllocatorRef allocator = CFGetAllocator(key); - return SecRSAPrivateKeyCreatePKCS1(allocator, fullkey); -} - -static OSStatus SecRSAPrivateKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) -{ - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - - CFAllocatorRef allocator = CFGetAllocator(key); - *serialized = SecRSAPublicKeyCreatePKCS1(allocator, fullkey); - - if (NULL == *serialized) - return errSecDecode; - else - return errSecSuccess; -} - - -static CFDictionaryRef SecRSAPrivateKeyCopyAttributeDictionary(SecKeyRef key) { - CFDictionaryRef dict = NULL; - CFDataRef fullKeyBlob = NULL; - - /* PKCS1 encode the key pair. */ - fullKeyBlob = SecRSAPrivateKeyCopyPKCS1(key); - require(fullKeyBlob, errOut); - - dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeRSA, fullKeyBlob); - -errOut: - CFReleaseSafe(fullKeyBlob); - - return dict; -} - -static CFStringRef SecRSAPrivateKeyCopyDescription(SecKeyRef key){ - - return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( ""), SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); - -} -SecKeyDescriptor kSecRSAPrivateKeyDescriptor = { - kSecKeyDescriptorVersion, - "RSAPrivateKey", - ccrsa_full_ctx_size(kMaximumRSAKeyBytes), /* extraBytes */ - SecRSAPrivateKeyInit, - SecRSAPrivateKeyDestroy, - SecRSAPrivateKeyRawSign, - NULL, /* SecKeyRawVerifyMethod */ - NULL, /* SecKeyEncryptMethod */ - SecRSAPrivateKeyRawDecrypt, - NULL, /* SecKeyComputeMethod */ - SecRSAPrivateKeyBlockSize, - SecRSAPrivateKeyCopyAttributeDictionary, - SecRSAPrivateKeyCopyDescription, - NULL, - SecRSAPrivateKeyCopyPublicSerialization, -}; - -/* Private Key API functions. */ -SecKeyRef SecKeyCreateRSAPrivateKey(CFAllocatorRef allocator, - const uint8_t *keyData, CFIndex keyDataLength, - SecKeyEncoding encoding) { - return SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, keyData, - keyDataLength, encoding); -} - - -OSStatus SecRSAKeyGeneratePair(CFDictionaryRef parameters, - SecKeyRef *rsaPublicKey, SecKeyRef *rsaPrivateKey) { - OSStatus status = errSecParam; - - CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */ - - SecKeyRef pubKey = NULL; - SecKeyRef privKey = SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, - (const void*) parameters, 0, kSecGenerateKey); - - require(privKey, errOut); - - /* Create SecKeyRef's from the pkcs1 encoded keys. */ - pubKey = SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, - privKey->key, 0, kSecExtractPublicFromPrivate); - - require(pubKey, errOut); - - if (rsaPublicKey) { - *rsaPublicKey = pubKey; - pubKey = NULL; - } - if (rsaPrivateKey) { - *rsaPrivateKey = privKey; - privKey = NULL; - } - - status = errSecSuccess; - -errOut: - CFReleaseSafe(pubKey); - CFReleaseSafe(privKey); - - return status; -}