X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..07691282a056c4efea71e1e505527601e8cc166b:/OSX/shared_regressions/si-44-seckey-rsa.m diff --git a/OSX/shared_regressions/si-44-seckey-rsa.m b/OSX/shared_regressions/si-44-seckey-rsa.m index d38b4c75..23f58798 100644 --- a/OSX/shared_regressions/si-44-seckey-rsa.m +++ b/OSX/shared_regressions/si-44-seckey-rsa.m @@ -24,6 +24,16 @@ #import +#import +#import +#import + +#import +#import +#import +#import +#import + #include "shared_regressions.h" static NSData *decryptAndUnpad(SecKeyRef privateKey, SecKeyAlgorithm algorithm, NSData *ciphertext, NSError **error) { @@ -141,6 +151,100 @@ static const int TestCountEncryption = TestCountEncryptKeypairRun + (TestCountEncryptRun * 6) + (1 * 1) + TestCountEncryptKeypairRun + (TestCountEncryptRun * 7) + (1 * 0); +static void test_pss_sign_run(SecKeyRef privateKey, SecKeyAlgorithm algorithm, SecKeyAlgorithm digestAlgorithm, + const struct ccdigest_info *di) { + NSError *error; + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey(privateKey)); + NSData *message = [NSData dataWithBytes:"1234" length:4]; + NSMutableData *digest = [NSMutableData dataWithLength:di->output_size]; + ccdigest(di, message.length, message.bytes, digest.mutableBytes); + + // Verify algorithm's availability + ok(SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, algorithm), "algorithm %@ available on key %@", algorithm, privateKey); + ok(SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, digestAlgorithm), "algorithm %@ available on key %@", digestAlgorithm, privateKey); + + // Calculate signature of the message using SecKey + error = nil; + NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, algorithm, (CFDataRef)message, (void *)&error)); + ok(signature != nil, "sign message with algorithm %@: error %@", algorithm, error); + + // Verify signature of the message using SecKey + error = nil; + Boolean verified = SecKeyVerifySignature((SecKeyRef)publicKey, algorithm, (CFDataRef)message, (CFDataRef)signature, (void *)&error); + ok(verified, "signature verified for algorithm %@: error %@", algorithm, error); + + // Calculate signature of the digest using SecKey + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, digestAlgorithm, (CFDataRef)digest, (void *)&error)); + ok(signature != nil, "sign digest with algorithm %@: error %@", digestAlgorithm, error); + + // Verify signature of the digest using CC + NSData *pubData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, (void *)&error)); + ok(pubData != nil, "export public key: error %@", error); + cc_size n = ccrsa_import_pub_n(pubData.length, pubData.bytes); + ccrsa_pub_ctx_decl(ccn_sizeof_n(n), ccpub); + ccrsa_ctx_n(ccpub) = n; + int err = ccrsa_import_pub(ccpub, pubData.length, pubData.bytes); + is(err, 0, "ccrsa_import_pub(key=%@) failed", publicKey); + + bool valid = false; + err = ccrsa_verify_pss(ccpub, di, di, di->output_size, digest.bytes, signature.length, signature.bytes, di->output_size, &valid); + is(err, 0, "ccrsa_verify_pss(%@) failed", algorithm); + ok(valid, "ccrsa verify signature (alg %@)", algorithm); + + // Calculate signature of the digest using CC + error = nil; + NSData *privData = CFBridgingRelease(SecKeyCopyExternalRepresentation(privateKey, (void *)&error)); + ok(privData != nil, "export private key: error %@", error); + n = ccrsa_import_priv_n(privData.length, privData.bytes); + ccrsa_full_ctx_decl(ccn_sizeof_n(n), ccpriv); + ccrsa_ctx_n(ccpriv) = n; + err = ccrsa_import_priv(ccpriv, privData.length, privData.bytes); + is(err, 0, "ccrsa_import_priv(key=%@) failed", privateKey); + + NSMutableData *ccSig = [NSMutableData dataWithLength:SecKeyGetBlockSize(privateKey)]; + size_t sigSize = ccSig.length; + err = ccrsa_sign_pss(ccpriv, di, di, di->output_size, ccrng(NULL), digest.length, digest.bytes, &sigSize, ccSig.mutableBytes); + is(err, 0, "ccrsa_sign_pss(%@) failed", digestAlgorithm); + is(sigSize, ccSig.length, "unexpected signature size for algorithm %@", digestAlgorithm); + + // Verify signature of the digest using SecKey + error = nil; + verified = SecKeyVerifySignature((SecKeyRef)publicKey, digestAlgorithm, (CFDataRef)digest, (CFDataRef)ccSig, (void *)&error); + ok(verified, "signature verified for algorithm %@: error %@", digestAlgorithm, error); +} +static const int TestCountPSSSignRun = 14; + +static void test_pss_sign() { + NSError *error; + NSDictionary *params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @1024}; + + error = nil; + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privateKey != nil, "generate private key (error %@)", error); + + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA1, kSecKeyAlgorithmRSASignatureDigestPSSSHA1, ccsha1_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA224, kSecKeyAlgorithmRSASignatureDigestPSSSHA224, ccsha224_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA256, kSecKeyAlgorithmRSASignatureDigestPSSSHA256, ccsha256_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA384, kSecKeyAlgorithmRSASignatureDigestPSSSHA384, ccsha384_di()); + + // RSASSA-PSS requires hlen + slen + 2 size modulus, so it requires at least 1040bit keys, and should not be available for 1024b keys. + ok(!SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, kSecKeyAlgorithmRSASignatureDigestPSSSHA512)); + ok(!SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, kSecKeyAlgorithmRSASignatureMessagePSSSHA512)); + + error = nil; + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048}; + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privateKey != nil, "generate private key (error %@)", error); + + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA1, kSecKeyAlgorithmRSASignatureDigestPSSSHA1, ccsha1_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA224, kSecKeyAlgorithmRSASignatureDigestPSSSHA224, ccsha224_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA256, kSecKeyAlgorithmRSASignatureDigestPSSSHA256, ccsha256_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA384, kSecKeyAlgorithmRSASignatureDigestPSSSHA384, ccsha384_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA512, kSecKeyAlgorithmRSASignatureDigestPSSSHA512, ccsha512_di()); +} +static const int TestCountPSSSign = 1 + TestCountPSSSignRun * 4 + 2 + 1 + TestCountPSSSignRun * 5; + static void test_bad_input(NSInteger keySizeInBits, NSInteger inputSize, SecKeyAlgorithm algorithm) { NSError *error; NSDictionary *params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @(keySizeInBits)}; @@ -177,16 +281,69 @@ static void test_bad_input_size() { } static const int TestCountBadInputSize = TestCountBadInputSizeStep * 8; +static void test_bad_signature() { + NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048 }; + NSError *error; + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privateKey, "Generate RSA-2048 temporary key, err %@", error); + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); + ok(publicKey, "Get public key from private key"); + +#if TARGET_OS_IPHONE + SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1; +#else + SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; +#endif + + char digest[20] = "digest"; + NSData *digestData = [NSData dataWithBytes:digest length:sizeof(digest)]; + NSData *signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privateKey, algorithm, (CFDataRef)digestData, (void *)&error)); + ok(signature, "Sign digest, err %@", error); + + bool result = SecKeyVerifySignature((SecKeyRef)publicKey, algorithm, (CFDataRef)digestData, (CFDataRef)signature, (void *)&error); + ok(result, "Verify signature, err %@", error); + + OSStatus status = SecKeyRawVerify((SecKeyRef)publicKey, kSecPaddingPKCS1SHA1, (const uint8_t *)digest, sizeof(digest), signature.bytes, signature.length); + ok_status(status, "Raw verify correct signature"); + + status = SecKeyRawVerify((SecKeyRef)publicKey, kSecPaddingPKCS1SHA1, (const uint8_t *)digest, sizeof(digest), (void * _Nonnull)NULL, 0); + is_status(status, errSSLCrypto, "NULL signature failure"); + + const SecAsn1AlgId algId = { .algorithm = CSSMOID_SHA1WithRSA }; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1, (CFDataRef)digestData, (void *)&error)); + ok(signature, "Sign message, err %@", error); + + status = SecKeyDigestAndVerify((__bridge SecKeyRef)publicKey, &algId, (const uint8_t *)digest, sizeof(digest), signature.bytes, signature.length); + ok_status(status, "Raw verify correct signature"); + + status = SecKeyDigestAndVerify((__bridge SecKeyRef)publicKey, &algId, (const uint8_t *)digest, sizeof(digest), (void * _Nonnull)NULL, 0); + is_status(status, errSSLCrypto, "NULL signature failure"); + + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, (CFDataRef)digestData, (void *)&error)); + ok(signature, "Sign message, err %@", error); + + status = SecKeyVerifyDigest((__bridge SecKeyRef)publicKey, &algId, (const uint8_t *)digest, sizeof(digest), signature.bytes, signature.length); + ok_status(status, "Raw verify correct signature"); + + status = SecKeyVerifyDigest((__bridge SecKeyRef)publicKey, &algId, (const uint8_t *)digest, sizeof(digest), (void * _Nonnull)NULL, 0); + is_status(status, errSSLCrypto, "NULL signature failure"); +} +static const int TestCountBadSignature = 12; + static const int TestCount = TestCountEncryption + -TestCountBadInputSize; +TestCountPSSSign + +TestCountBadInputSize + +TestCountBadSignature; int si_44_seckey_rsa(int argc, char *const *argv) { plan_tests(TestCount); @autoreleasepool { test_encryption(); + test_pss_sign(); test_bad_input_size(); + test_bad_signature(); } return 0;