blob: 4a9c7299ec388a7af043fb563324f2630e6bb204 [file] [log] [blame]
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "Test.h"
#if HAVE(RSA_BSSA)
#include "ASN1Utilities.h"
#include "CoreCryptoSPI.h"
#include <WebCore/PrivateClickMeasurement.h>
#include <wtf/spi/cocoa/SecuritySPI.h>
namespace TestWebKitAPI {
using namespace WebCore;
TEST(PrivateClickMeasurement, ValidBlindedSecret)
{
auto ephemeralNonce = PrivateClickMeasurement::EphemeralNonce { "ABCDEFabcdef0123456789"_s };
EXPECT_TRUE(ephemeralNonce.isValid());
WebCore::PrivateClickMeasurement pcm(
WebCore::PrivateClickMeasurement::SourceID({ }),
WebCore::PrivateClickMeasurement::SourceSite(URL()),
WebCore::PrivateClickMeasurement::AttributionDestinationSite(URL()),
{ },
WallTime::now(),
WebCore::PrivateClickMeasurement::AttributionEphemeral::No
);
pcm.setEphemeralSourceNonce(WTFMove(ephemeralNonce));
// Generate the server key pair.
size_t modulusNBits = 4096;
int error = 0;
struct ccrng_state* rng = ccrng(&error);
EXPECT_EQ(error, CCERR_OK);
const uint8_t e[] = { 0x1, 0x00, 0x01 };
ccrsa_full_ctx_decl(ccn_sizeof(modulusNBits), rsaPrivateKey);
error = ccrsa_generate_key(modulusNBits, rsaPrivateKey, sizeof(e), e, rng);
EXPECT_EQ(error, CCERR_OK);
ccrsa_pub_ctx_t rsaPublicKey = ccrsa_ctx_public(rsaPrivateKey);
size_t modulusNBytes = cc_ceiling(ccrsa_pubkeylength(rsaPublicKey), 8);
const struct ccrsabssa_ciphersuite *ciphersuite = &ccrsabssa_ciphersuite_rsa4096_sha384;
size_t exportSize = ccder_encode_rsa_pub_size(rsaPublicKey);
Vector<uint8_t> rawKeyBytes(exportSize);
ccder_encode_rsa_pub(rsaPublicKey, rawKeyBytes.data(), rawKeyBytes.data() + exportSize);
auto wrappedKeyBytes = wrapPublicKeyWithRSAPSSOID(WTFMove(rawKeyBytes));
// Continue the test.
auto errorMessage = pcm.calculateAndUpdateSourceUnlinkableToken(base64URLEncodeToString(wrappedKeyBytes.data(), wrappedKeyBytes.size()));
EXPECT_FALSE(errorMessage);
auto sourceUnlinkableToken = pcm.tokenSignatureJSON();
EXPECT_EQ(sourceUnlinkableToken->asObject()->size(), 4ul);
EXPECT_STREQ(sourceUnlinkableToken->getString("source_engagement_type"_s).utf8().data(), "click");
EXPECT_STREQ(sourceUnlinkableToken->getString("source_nonce"_s).utf8().data(), "ABCDEFabcdef0123456789");
EXPECT_FALSE(sourceUnlinkableToken->getString("source_unlinkable_token"_s).isEmpty());
EXPECT_EQ(sourceUnlinkableToken->getInteger("version"_s), 3);
// Generate the signature.
auto blindedMessage = base64URLDecode(sourceUnlinkableToken->getString("source_unlinkable_token"_s));
auto blindedSignature = adoptNS([[NSMutableData alloc] initWithLength:modulusNBytes]);
ccrsabssa_sign_blinded_message(ciphersuite, rsaPrivateKey, blindedMessage->data(), blindedMessage->size(), static_cast<uint8_t *>([blindedSignature mutableBytes]), [blindedSignature length], rng);
// Continue the test.
errorMessage = pcm.calculateAndUpdateSourceSecretToken(base64URLEncodeToString([blindedSignature bytes], [blindedSignature length]));
EXPECT_FALSE(errorMessage);
auto& persistentToken = pcm.sourceSecretToken();
EXPECT_TRUE(persistentToken);
EXPECT_FALSE(persistentToken->tokenBase64URL.isEmpty());
EXPECT_FALSE(persistentToken->keyIDBase64URL.isEmpty());
EXPECT_FALSE(persistentToken->signatureBase64URL.isEmpty());
}
} // namespace TestWebKitAPI
#endif // EHAVE(RSA_BSSA)