]> git.saurik.com Git - apple/security.git/blobdiff - OSX/shared_regressions/si-44-seckey-rsa.m
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / shared_regressions / si-44-seckey-rsa.m
index d38b4c75bcb399d4a49773e7f866b3b08ff4eccb..23f587980ebe6ec532f02b086ea0cd50482345ab 100644 (file)
 
 #import <Foundation/Foundation.h>
 
+#import <Security/SecKeyPriv.h>
+#import <Security/SecItemPriv.h>
+#import <Security/oidsalg.h>
+
+#import <corecrypto/ccrng.h>
+#import <corecrypto/ccsha1.h>
+#import <corecrypto/ccsha2.h>
+#import <corecrypto/ccdigest.h>
+#import <corecrypto/ccrsa.h>
+
 #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;