Move URL from WebCore to WTF
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / mac / SSLKeyGenerator.mm
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27
28 #import <Security/SecAsn1Coder.h>
29 #import <Security/SecAsn1Templates.h>
30 #import <WebCore/LocalizedStrings.h>
31 #import <WebCore/SSLKeyGenerator.h>
32 #import <wtf/MainThread.h>
33 #import <wtf/Scope.h>
34 #import <wtf/URL.h>
35 #import <wtf/spi/cocoa/SecuritySPI.h>
36 #import <wtf/text/Base64.h>
37
38 #if USE(APPLE_INTERNAL_SDK)
39 #include <Security/SecKeyPriv.h>
40 #else
41 extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5;
42 #endif
43
44 namespace TestWebKitAPI {
45
46 struct PublicKeyAndChallenge {
47     SecAsn1PubKeyInfo subjectPublicKeyInfo;
48     SecAsn1Item challenge;
49 };
50
51 struct SignedPublicKeyAndChallenge {
52     PublicKeyAndChallenge publicKeyAndChallenge;
53     SecAsn1AlgId algorithmIdentifier;
54     SecAsn1Item signature;
55 };
56
57 const SecAsn1Template publicKeyAndChallengeTemplate[] {
58     { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PublicKeyAndChallenge) },
59     { SEC_ASN1_INLINE, offsetof(PublicKeyAndChallenge, subjectPublicKeyInfo), kSecAsn1SubjectPublicKeyInfoTemplate, 0},
60     { SEC_ASN1_INLINE, offsetof(PublicKeyAndChallenge, challenge), kSecAsn1IA5StringTemplate, 0 },
61     { 0, 0, 0, 0}
62 };
63
64 const SecAsn1Template signedPublicKeyAndChallengeTemplate[] {
65     { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SignedPublicKeyAndChallenge) },
66     { SEC_ASN1_INLINE, offsetof(SignedPublicKeyAndChallenge, publicKeyAndChallenge), publicKeyAndChallengeTemplate, 0 },
67     { SEC_ASN1_INLINE, offsetof(SignedPublicKeyAndChallenge, algorithmIdentifier), kSecAsn1AlgorithmIDTemplate, 0 },
68     { SEC_ASN1_BIT_STRING, offsetof(SignedPublicKeyAndChallenge, signature), 0, 0 },
69     { 0, 0, 0, 0 }
70 };
71
72 const URL url = URL(URL(), "http://www.webkit.org/");
73
74 class SSLKeyGeneratorTest : public testing::Test {
75 public:
76     virtual void SetUp()
77     {
78         WTF::initializeMainThread();
79     }
80
81     virtual void TearDown()
82     {
83         SecItemDelete((__bridge CFDictionaryRef) @{
84             (id)kSecClass: (id)kSecClassKey,
85             (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
86             (id)kSecAttrLabel: WebCore::keygenKeychainItemName(url.host().toString()),
87         });
88         SecItemDelete((__bridge CFDictionaryRef) @{
89             (id)kSecClass: (id)kSecClassKey,
90             (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic,
91             (id)kSecAttrLabel: WebCore::keygenKeychainItemName(url.host().toString()),
92         });
93     }
94 };
95
96 TEST_F(SSLKeyGeneratorTest, DefaultTest)
97 {
98     char challenge[] = "0123456789";
99     auto rawResult = WebCore::signedPublicKeyAndChallengeString(0, challenge, url);
100     ASSERT_FALSE(rawResult.isEmpty());
101     Vector<uint8_t> derResult;
102     ASSERT_TRUE(base64Decode(rawResult, derResult));
103
104     SecAsn1CoderRef coder = nullptr;
105     ASSERT_EQ(errSecSuccess, SecAsn1CoderCreate(&coder));
106     auto releaseCoder = makeScopeExit([&coder] {
107         SecAsn1CoderRelease(coder);
108     });
109
110     SignedPublicKeyAndChallenge decodedResult { };
111     SecAsn1Item derResultItem { derResult.size(), derResult.data() };
112     ASSERT_EQ(errSecSuccess, SecAsn1DecodeData(coder, &derResultItem, signedPublicKeyAndChallengeTemplate, &decodedResult));
113
114     // Check challenge
115     EXPECT_FALSE(memcmp(challenge, decodedResult.publicKeyAndChallenge.challenge.Data, sizeof(challenge)));
116
117     // Check signature
118     RetainPtr<SecKeyRef> publicKey = nullptr;
119     {
120         NSDictionary* options = @{
121             (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
122             (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic,
123             (id)kSecAttrKeySizeInBits: @2048,
124         };
125         CFErrorRef errorRef = nullptr;
126         publicKey = adoptCF(SecKeyCreateWithData(
127             adoptCF(CFDataCreate(NULL, decodedResult.publicKeyAndChallenge.subjectPublicKeyInfo.subjectPublicKey.Data, decodedResult.publicKeyAndChallenge.subjectPublicKeyInfo.subjectPublicKey.Length)).get(),
128             (__bridge CFDictionaryRef)options,
129             &errorRef
130         ));
131         ASSERT_FALSE(errorRef);
132     }
133
134     SecAsn1Item dataToVerify { 0, nullptr };
135     ASSERT_EQ(errSecSuccess, SecAsn1EncodeItem(coder, &decodedResult.publicKeyAndChallenge, publicKeyAndChallengeTemplate, &dataToVerify));
136
137     // Signature's Length is in bits, we need it in bytes.
138     EXPECT_TRUE(SecKeyVerifySignature(publicKey.get(), kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, adoptCF(CFDataCreate(NULL, dataToVerify.Data, dataToVerify.Length)).get(), adoptCF(CFDataCreate(NULL, decodedResult.signature.Data, decodedResult.signature.Length / 8)).get(), NULL));
139
140     // Check OIDs
141     EXPECT_FALSE(memcmp(oidMd5Rsa.data, decodedResult.algorithmIdentifier.algorithm.Data, oidMd5Rsa.length));
142     EXPECT_FALSE(memcmp(oidRsa.data, decodedResult.publicKeyAndChallenge.subjectPublicKeyInfo.algorithm.algorithm.Data, oidRsa.length));
143
144 }
145
146 } // namespace TestWebKitAPI