Title: [287015] trunk/Source/WebCore
Revision
287015
Author
[email protected]
Date
2021-12-14 00:18:02 -0800 (Tue, 14 Dec 2021)

Log Message

Add web push message decryption routines
https://bugs.webkit.org/show_bug.cgi?id=233903

Reviewed by Brady Eidson.

Source/WebCore:

This adds routines to decrypt push payloads encoded with the aes128gcm and aesgcm schemes.
The crypto primitives that we depend are implemented in PushCrypto, while the logic to use
those primitives to decrypt message payloads is in PushMessageCrypto.

Test: TestWebKitAPI.PushMessageCrypto

* Headers.cmake:
* Modules/push-api/PushCrypto.cpp: Added.
(WebCore::PushCrypto::P256DHKeyPair::generate):
(WebCore::PushCrypto::validateP256DHPublicKey):
(WebCore::PushCrypto::computeP256DHSharedSecret):
(WebCore::PushCrypto::hmacSHA256):
(WebCore::PushCrypto::decryptAES128GCM):
* Modules/push-api/PushCrypto.h: Added.
* Modules/push-api/PushManager.cpp:
(WebCore::PushManager::subscribe):
* Modules/push-api/PushMessageCrypto.cpp: Added.
(WebCore::PushCrypto::ClientKeys::generate):
(WebCore::PushCrypto::areClientKeyLengthsValid):
(WebCore::PushCrypto::computeAES128GCMPaddingLength):
(WebCore::PushCrypto::decryptAES128GCMPayload):
(WebCore::PushCrypto::computeAESGCMPaddingLength):
(WebCore::PushCrypto::decryptAESGCMPayload):
* Modules/push-api/PushMessageCrypto.h: Added.
* Modules/push-api/cocoa/PushCryptoCocoa.cpp: Added.
(WebCore::PushCrypto::P256DHKeyPair::generate):
(WebCore::PushCrypto::validateP256DHPublicKey):
(WebCore::PushCrypto::computeP256DHSharedSecret):
(WebCore::PushCrypto::hmacSHA256):
(WebCore::PushCrypto::decryptAES128GCM):
* Sources.txt:
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:

Source/WebCore/PAL:

* pal/spi/cocoa/CommonCryptoSPI.h: Add AES-GCM decryption SPI.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (287014 => 287015)


--- trunk/Source/WebCore/ChangeLog	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/ChangeLog	2021-12-14 08:18:02 UTC (rev 287015)
@@ -1,3 +1,44 @@
+2021-12-14  Ben Nham  <[email protected]>
+
+        Add web push message decryption routines
+        https://bugs.webkit.org/show_bug.cgi?id=233903
+
+        Reviewed by Brady Eidson.
+
+        This adds routines to decrypt push payloads encoded with the aes128gcm and aesgcm schemes.
+        The crypto primitives that we depend are implemented in PushCrypto, while the logic to use
+        those primitives to decrypt message payloads is in PushMessageCrypto.
+
+        Test: TestWebKitAPI.PushMessageCrypto
+
+        * Headers.cmake:
+        * Modules/push-api/PushCrypto.cpp: Added.
+        (WebCore::PushCrypto::P256DHKeyPair::generate):
+        (WebCore::PushCrypto::validateP256DHPublicKey):
+        (WebCore::PushCrypto::computeP256DHSharedSecret):
+        (WebCore::PushCrypto::hmacSHA256):
+        (WebCore::PushCrypto::decryptAES128GCM):
+        * Modules/push-api/PushCrypto.h: Added.
+        * Modules/push-api/PushManager.cpp:
+        (WebCore::PushManager::subscribe):
+        * Modules/push-api/PushMessageCrypto.cpp: Added.
+        (WebCore::PushCrypto::ClientKeys::generate):
+        (WebCore::PushCrypto::areClientKeyLengthsValid):
+        (WebCore::PushCrypto::computeAES128GCMPaddingLength):
+        (WebCore::PushCrypto::decryptAES128GCMPayload):
+        (WebCore::PushCrypto::computeAESGCMPaddingLength):
+        (WebCore::PushCrypto::decryptAESGCMPayload):
+        * Modules/push-api/PushMessageCrypto.h: Added.
+        * Modules/push-api/cocoa/PushCryptoCocoa.cpp: Added.
+        (WebCore::PushCrypto::P256DHKeyPair::generate):
+        (WebCore::PushCrypto::validateP256DHPublicKey):
+        (WebCore::PushCrypto::computeP256DHSharedSecret):
+        (WebCore::PushCrypto::hmacSHA256):
+        (WebCore::PushCrypto::decryptAES128GCM):
+        * Sources.txt:
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2021-12-13  Carlos Garcia Campos  <[email protected]>
 
         [GTK][a11y] Handle the Embedded method sent by AtkSocket from AccessibilityRootAtspi

Modified: trunk/Source/WebCore/Headers.cmake (287014 => 287015)


--- trunk/Source/WebCore/Headers.cmake	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/Headers.cmake	2021-12-14 08:18:02 UTC (rev 287015)
@@ -290,6 +290,8 @@
     Modules/permissions/PermissionObserver.h
     Modules/permissions/PermissionState.h
 
+    Modules/push-api/PushCrypto.h
+    Modules/push-api/PushMessageCrypto.h
     Modules/push-api/PushPermissionState.h
     Modules/push-api/PushSubscriptionData.h
 

Added: trunk/Source/WebCore/Modules/push-api/PushCrypto.cpp (0 => 287015)


--- trunk/Source/WebCore/Modules/push-api/PushCrypto.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/push-api/PushCrypto.cpp	2021-12-14 08:18:02 UTC (rev 287015)
@@ -0,0 +1,66 @@
+/*
+ * 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 "PushCrypto.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include <wtf/Scope.h>
+
+namespace WebCore::PushCrypto {
+
+#if !PLATFORM(COCOA)
+
+P256DHKeyPair P256DHKeyPair::generate(void)
+{
+    return { };
+}
+
+bool validateP256DHPublicKey(Span<const uint8_t>)
+{
+    return false;
+}
+
+std::optional<Vector<uint8_t>> computeP256DHSharedSecret(Span<const uint8_t> publicKey, const P256DHKeyPair& keyPair)
+{
+    return std::nullopt;
+}
+
+Vector<uint8_t> hmacSHA256(Span<const uint8_t>, Span<const uint8_t>)
+{
+    return { };
+}
+
+std::optional<Vector<uint8_t>> decryptAES128GCM(Span<const uint8_t>, Span<const uint8_t>, Span<const uint8_t>)
+{
+    return std::nullopt;
+}
+
+#endif // !PLATFORM(COCOA)
+
+} // namespace WebCore::PushCrypto
+
+#endif // ENABLE(SERVICE_WORKER)

Added: trunk/Source/WebCore/Modules/push-api/PushCrypto.h (0 => 287015)


--- trunk/Source/WebCore/Modules/push-api/PushCrypto.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/push-api/PushCrypto.h	2021-12-14 08:18:02 UTC (rev 287015)
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(SERVICE_WORKER)
+
+#include <wtf/Forward.h>
+#include <wtf/Span.h>
+#include <wtf/Vector.h>
+
+namespace WebCore::PushCrypto {
+
+static constexpr size_t p256dhPublicKeyLength = 65;
+static constexpr size_t p256dhPrivateKeyLength = 32;
+static constexpr size_t p256dhSharedSecretLength = 32;
+static constexpr size_t sha256DigestLength = 32;
+static constexpr size_t aes128GCMTagLength = 16;
+
+struct P256DHKeyPair {
+    Vector<uint8_t> publicKey;
+    Vector<uint8_t> privateKey;
+
+    static P256DHKeyPair generate(void);
+};
+
+bool validateP256DHPublicKey(Span<const uint8_t> publicKey);
+
+WEBCORE_EXPORT std::optional<Vector<uint8_t>> computeP256DHSharedSecret(Span<const uint8_t> publicKey, const P256DHKeyPair&);
+
+WEBCORE_EXPORT Vector<uint8_t> hmacSHA256(Span<const uint8_t> key, Span<const uint8_t> message);
+
+WEBCORE_EXPORT std::optional<Vector<uint8_t>> decryptAES128GCM(Span<const uint8_t> key, Span<const uint8_t> iv, Span<const uint8_t> cipherTextWithTag);
+
+} // namespace WebCore::PushCrypto
+
+#endif // ENABLE(SERVICE_WORKER)

Modified: trunk/Source/WebCore/Modules/push-api/PushManager.cpp (287014 => 287015)


--- trunk/Source/WebCore/Modules/push-api/PushManager.cpp	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/Modules/push-api/PushManager.cpp	2021-12-14 08:18:02 UTC (rev 287015)
@@ -28,11 +28,11 @@
 
 #if ENABLE(SERVICE_WORKER)
 
-#include "CryptoKeyEC.h"
 #include "EventLoop.h"
 #include "Exception.h"
 #include "JSPushPermissionState.h"
 #include "JSPushSubscription.h"
+#include "PushCrypto.h"
 #include "ScriptExecutionContext.h"
 #include "ServiceWorkerRegistration.h"
 #include <wtf/IsoMallocInlines.h>
@@ -101,14 +101,7 @@
             return;
         }
 
-#if ENABLE(WEB_CRYPTO)
-        auto keyData = keyDataResult.returnValue();
-        auto key = CryptoKeyEC::importRaw(CryptoAlgorithmIdentifier::ECDSA, "P-256"_s, WTFMove(keyData), false, CryptoKeyUsageVerify);
-#else
-        auto key = nullptr;
-#endif
-
-        if (!key) {
+        if (!PushCrypto::validateP256DHPublicKey(keyDataResult.returnValue())) {
             promise.reject(Exception { InvalidAccessError, "applicationServerKey must contain a valid P-256 public key"_s });
             return;
         }

Added: trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.cpp (0 => 287015)


--- trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.cpp	2021-12-14 08:18:02 UTC (rev 287015)
@@ -0,0 +1,305 @@
+/*
+ * 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 "PushMessageCrypto.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "PushCrypto.h"
+#include <wtf/ByteOrder.h>
+#include <wtf/CryptographicallyRandomNumber.h>
+
+namespace WebCore::PushCrypto {
+
+// Arbitrary limit that's larger than the largest payload APNS should ever give us.
+static constexpr size_t maxPushPayloadLength = 65535;
+
+// From RFC8291.
+static constexpr size_t saltLength = 16;
+static constexpr size_t sharedAuthSecretLength = 16;
+
+ClientKeys ClientKeys::generate()
+{
+    uint8_t sharedAuthSecret[sharedAuthSecretLength];
+    cryptographicallyRandomValues(sharedAuthSecret, sizeof(sharedAuthSecret));
+
+    return ClientKeys {
+        P256DHKeyPair::generate(),
+        Vector<uint8_t> { sharedAuthSecret, sizeof(sharedAuthSecret) }
+    };
+}
+
+static bool areClientKeyLengthsValid(const ClientKeys& clientKeys)
+{
+    return clientKeys.clientP256DHKeyPair.publicKey.size() == p256dhPublicKeyLength && clientKeys.clientP256DHKeyPair.privateKey.size() == p256dhPrivateKeyLength && clientKeys.sharedAuthSecret.size() == sharedAuthSecretLength;
+}
+
+static size_t computeAES128GCMPaddingLength(const uint8_t *begin, size_t length)
+{
+    /*
+     * Compute padding length as defined in RFC8188 Section 2:
+     *
+     *   +-----------+-----+
+     *   |   data    | pad |
+     *   +-----------+-----+
+     *
+     * pad must be of non-zero length and is a delimiter octet (0x02) followed by any number of 0x00 octets.
+     */
+    if (!length)
+        return SIZE_MAX;
+
+    const uint8_t* end = begin + length;
+    const uint8_t* cur = end - 1;
+    while (cur > begin && (*cur == 0x00))
+        --cur;
+    if (*cur != 0x02)
+        return SIZE_MAX;
+
+    return end - cur;
+}
+
+std::optional<Vector<uint8_t>> decryptAES128GCMPayload(const ClientKeys& clientKeys, Span<const uint8_t> payload)
+{
+    if (!areClientKeyLengthsValid(clientKeys))
+        return std::nullopt;
+
+    // Extract encryption parameters from header as described in RFC8188.
+    struct PayloadHeader {
+        uint8_t salt[saltLength];
+        uint8_t ignored[4];
+        uint8_t keyLength;
+        uint8_t serverPublicKey[p256dhPublicKeyLength];
+    };
+    static_assert(sizeof(PayloadHeader) == 86);
+    static constexpr size_t minPushPayloadLength = sizeof(PayloadHeader) + 1 /* minPaddingLength */ + aes128GCMTagLength;
+
+    if (payload.size() < minPushPayloadLength || payload.size() > maxPushPayloadLength)
+        return std::nullopt;
+
+    PayloadHeader header;
+    memcpy(&header, payload.data(), sizeof(header));
+
+    if (header.keyLength != p256dhPublicKeyLength)
+        return std::nullopt;
+
+    /*
+     * The rest of the comments are snippets from RFC8291 3.4.
+     *
+     * -- For a user agent:
+     * ecdh_secret = ECDH(ua_private, as_public)
+     */
+    auto ecdhSecretResult = computeP256DHSharedSecret(header.serverPublicKey, clientKeys.clientP256DHKeyPair);
+    if (!ecdhSecretResult)
+        return std::nullopt;
+
+    /*
+     * # HKDF-Extract(salt=auth_secret, IKM=ecdh_secret)
+     * PRK_key = HMAC-SHA-256(auth_secret, ecdh_secret)
+     */
+    auto prkKey = hmacSHA256(clientKeys.sharedAuthSecret, *ecdhSecretResult);
+
+    /*
+     * # HKDF-Expand(PRK_key, key_info, L_key=32)
+     * key_info = "WebPush: info" || 0x00 || ua_public || as_public
+     * IKM = HMAC-SHA-256(PRK_key, key_info || 0x01)
+     */
+    struct KeyInfo {
+        uint8_t label[14] = { "WebPush: info" };
+        uint8_t clientKey[p256dhPublicKeyLength];
+        uint8_t serverKey[p256dhPublicKeyLength];
+        uint8_t end = 0x01;
+    };
+    static_assert(sizeof(KeyInfo) == 145);
+
+    KeyInfo keyInfo;
+    memcpy(keyInfo.clientKey, clientKeys.clientP256DHKeyPair.publicKey.data(), p256dhPublicKeyLength);
+    memcpy(keyInfo.serverKey, header.serverPublicKey, p256dhPublicKeyLength);
+
+    auto ikm = hmacSHA256(prkKey, Span(reinterpret_cast<uint8_t*>(&keyInfo), sizeof(keyInfo)));
+
+    /*
+     * # HKDF-Extract(salt, IKM)
+     * PRK = HMAC-SHA-256(salt, IKM)
+     */
+    auto prk = hmacSHA256(header.salt, ikm);
+
+    /*
+     * # HKDF-Expand(PRK, cek_info, L_cek=16)
+     * cek_info = "Content-Encoding: aes128gcm" || 0x00
+     * CEK = HMAC-SHA-256(PRK, cek_info || 0x01)[0..15]
+     */
+    static const uint8_t cekInfo[] = "Content-Encoding: aes128gcm\x00\x01";
+    auto cek = hmacSHA256(prk, Span(cekInfo, sizeof(cekInfo) - 1));
+    cek.shrink(16);
+
+    /*
+     * # HKDF-Expand(PRK, nonce_info, L_nonce=12)
+     * nonce_info = "Content-Encoding: nonce" || 0x00
+     * NONCE = HMAC-SHA-256(PRK, nonce_info || 0x01)[0..11]
+     */
+    static const uint8_t nonceInfo[] = "Content-Encoding: nonce\x00\x01";
+    auto nonce = hmacSHA256(prk, Span(nonceInfo, sizeof(nonceInfo) - 1));
+    nonce.shrink(12);
+
+    // Finally, decrypt with AES128GCM and return the unpadded plaintext.
+    auto cipherText = Span(payload.data() + sizeof(header), payload.size() - sizeof(header));
+    auto plainTextResult = decryptAES128GCM(cek, nonce, cipherText);
+    if (!plainTextResult)
+        return std::nullopt;
+
+    auto plainText = WTFMove(plainTextResult.value());
+    size_t paddingLength = computeAES128GCMPaddingLength(plainText.data(), plainText.size());
+    if (paddingLength == SIZE_MAX)
+        return std::nullopt;
+
+    plainText.shrink(plainText.size() - paddingLength);
+    return plainText;
+}
+
+static size_t computeAESGCMPaddingLength(const uint8_t *begin, size_t length)
+{
+    /*
+     * Compute padding length as defined in draft-ietf-httpbis-encryption-encoding-03:
+     *
+     *   +-----+-----------+
+     *   | pad |   data    |
+     *   +-----+-----------+
+     *
+     * Padding consists of a two octet unsigned integer in network byte order, followed by that
+     * number of 0x00 octets. The minimum padding size is 2 bytes.
+     */
+    if (length < 2)
+        return SIZE_MAX;
+
+    uint16_t paddingLength;
+    memcpy(&paddingLength, begin, 2);
+    paddingLength = ntohs(paddingLength);
+
+    const uint8_t* cur = begin + 2;
+    const uint8_t* end = begin + length;
+    uint16_t paddingLeft = paddingLength;
+    while (cur < end && (*cur == 0x0) && paddingLeft) {
+        ++cur;
+        --paddingLeft;
+    }
+
+    if (paddingLeft)
+        return SIZE_MAX;
+
+    return cur - begin;
+}
+
+std::optional<Vector<uint8_t>> decryptAESGCMPayload(const ClientKeys& clientKeys, Span<const uint8_t> serverP256DHPublicKey, Span<const uint8_t> salt, Span<const uint8_t> payload)
+{
+    if (!areClientKeyLengthsValid(clientKeys) || serverP256DHPublicKey.size() != p256dhPublicKeyLength || salt.size() != saltLength)
+        return std::nullopt;
+
+    // Padding must be at least the size of the two octet unsigned integer used in the padding scheme plus the size of the AES128GCM tag.
+    if (payload.size() < 2 + aes128GCMTagLength || payload.size() > maxPushPayloadLength)
+        return std::nullopt;
+
+    /*
+     * These comments are snippets from draft-ietf-webpush-encryption-04.
+     *
+     * -- For a User Agent:
+     * ecdh_secret = ECDH(ua_private, as_public)
+     */
+    auto ecdhSecretResult = computeP256DHSharedSecret(serverP256DHPublicKey, clientKeys.clientP256DHKeyPair);
+    if (!ecdhSecretResult)
+        return std::nullopt;
+
+    /*
+     * auth_info = "Content-Encoding: auth" || 0x00
+     * PRK_combine = HMAC-SHA-256(auth_secret, ecdh_secret)
+     * IKM = HMAC-SHA-256(PRK_combine, auth_info || 0x01)
+     * PRK = HMAC-SHA-256(salt, IKM)
+     */
+    static const uint8_t authInfo[] = "Content-Encoding: auth\x00\x01";
+    auto prkCombine = hmacSHA256(clientKeys.sharedAuthSecret, *ecdhSecretResult);
+    auto ikm = hmacSHA256(prkCombine, Span(authInfo, sizeof(authInfo) - 1));
+    auto prk = hmacSHA256(salt, ikm);
+
+    /*
+     * context = "P-256" || 0x00 ||
+     *           0x00 || 0x41 || ua_public ||
+     *           0x00 || 0x41 || as_public
+     *
+     * Note that we also append a 0x01 byte at the end here since the cek and nonce
+     * derivation functions below require that trailing 0x01 byte.
+     */
+    struct KeyDerivationContext {
+        uint8_t label[6] = { "P-256" };
+        uint8_t clientPublicKeyLength[2] = { 0, 0x41 };
+        uint8_t clientPublicKey[p256dhPublicKeyLength];
+        uint8_t serverPublicKeyLength[2] = { 0, 0x41 };
+        uint8_t serverPublicKey[p256dhPublicKeyLength];
+        uint8_t end = 0x01;
+    };
+    static_assert(sizeof(KeyDerivationContext) == 141);
+    KeyDerivationContext context;
+    memcpy(context.clientPublicKey, clientKeys.clientP256DHKeyPair.publicKey.data(), p256dhPublicKeyLength);
+    memcpy(context.serverPublicKey, serverP256DHPublicKey.data(), p256dhPublicKeyLength);
+
+    /*
+     * cek_info = "Content-Encoding: aesgcm" || 0x00 || context
+     * CEK = HMAC-SHA-256(PRK, cek_info || 0x01)[0..15]
+     */
+    static const uint8_t cekInfoHeader[] = "Content-Encoding: aesgcm";
+    uint8_t cekInfo[sizeof(cekInfoHeader) + sizeof(context)];
+    memcpy(cekInfo, cekInfoHeader, sizeof(cekInfoHeader));
+    memcpy(cekInfo + sizeof(cekInfoHeader), &context, sizeof(context));
+
+    auto cek = hmacSHA256(prk, cekInfo);
+    cek.shrink(16);
+
+    /*
+     * nonce_info = "Content-Encoding: nonce" || 0x00 || context
+     * NONCE = HMAC-SHA-256(PRK, nonce_info || 0x01)[0..11]
+     */
+    static const uint8_t nonceInfoHeader[] = "Content-Encoding: nonce";
+    uint8_t nonceInfo[sizeof(nonceInfoHeader) + sizeof(context)];
+    memcpy(nonceInfo, nonceInfoHeader, sizeof(nonceInfoHeader));
+    memcpy(nonceInfo + sizeof(nonceInfoHeader), &context, sizeof(context));
+
+    auto nonce = hmacSHA256(prk, nonceInfo);
+    nonce.shrink(12);
+
+    // Finally, decrypt with AES128GCM and return the unpadded plaintext.
+    auto plainTextResult = decryptAES128GCM(cek, nonce, payload);
+    if (!plainTextResult)
+        return std::nullopt;
+
+    auto plainText = WTFMove(plainTextResult.value());
+    size_t paddingLength = computeAESGCMPaddingLength(plainText.data(), plainText.size());
+    if (paddingLength == SIZE_MAX)
+        return std::nullopt;
+
+    return Vector<uint8_t> { plainText.data() + paddingLength, plainText.size() - paddingLength };
+}
+
+} // namespace WebCore::PushCrypto
+
+#endif // ENABLE(SERVICE_WORKER)

Added: trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.h (0 => 287015)


--- trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/push-api/PushMessageCrypto.h	2021-12-14 08:18:02 UTC (rev 287015)
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "PushCrypto.h"
+#include <wtf/Forward.h>
+#include <wtf/Span.h>
+#include <wtf/Vector.h>
+
+namespace WebCore::PushCrypto {
+
+struct ClientKeys {
+    P256DHKeyPair clientP256DHKeyPair;
+    Vector<uint8_t> sharedAuthSecret;
+
+    WEBCORE_EXPORT static ClientKeys generate();
+};
+
+// Decrypts a push payload encoded with the aes128gcm Content-Encoding as described in RFC8291.
+WEBCORE_EXPORT std::optional<Vector<uint8_t>> decryptAES128GCMPayload(const ClientKeys&, Span<const uint8_t> payload);
+
+// Decrypts a push payload encoded with the aesgcm Content-Encoding as described in draft-ietf-webpush-encryption-04.
+WEBCORE_EXPORT std::optional<Vector<uint8_t>> decryptAESGCMPayload(const ClientKeys&, Span<const uint8_t> serverP256DHPublicKey, Span<const uint8_t> salt, Span<const uint8_t> payload);
+
+} // namespace WebCore::PushCrypto
+
+#endif // ENABLE(SERVICE_WORKER)

Added: trunk/Source/WebCore/Modules/push-api/cocoa/PushCryptoCocoa.cpp (0 => 287015)


--- trunk/Source/WebCore/Modules/push-api/cocoa/PushCryptoCocoa.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/push-api/cocoa/PushCryptoCocoa.cpp	2021-12-14 08:18:02 UTC (rev 287015)
@@ -0,0 +1,132 @@
+/*
+ * 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 "PushCrypto.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include <CommonCrypto/CommonHMAC.h>
+#include <pal/spi/cocoa/CommonCryptoSPI.h>
+#include <wtf/Scope.h>
+
+namespace WebCore::PushCrypto {
+
+P256DHKeyPair P256DHKeyPair::generate(void)
+{
+    CCECCryptorRef ccPublicKey = nullptr;
+    CCECCryptorRef ccPrivateKey = nullptr;
+    auto releaser = WTF::makeScopeExit([&ccPublicKey, &ccPrivateKey]() {
+        if (ccPublicKey)
+            CCECCryptorRelease(ccPublicKey);
+        if (ccPrivateKey)
+            CCECCryptorRelease(ccPrivateKey);
+    });
+
+    CCCryptorStatus status = CCECCryptorGeneratePair(256, &ccPublicKey, &ccPrivateKey);
+    RELEASE_ASSERT(status == kCCSuccess);
+
+    uint8_t publicKey[p256dhPublicKeyLength];
+    size_t publicKeyLength = sizeof(publicKey);
+    status = CCECCryptorExportKey(kCCImportKeyBinary, publicKey, &publicKeyLength, ccECKeyPublic, ccPublicKey);
+    RELEASE_ASSERT(status == kCCSuccess && publicKeyLength == sizeof(publicKey));
+
+    // CommonCrypto expects the binary format to be 65 byte public key followed by the 32 byte private key, so we want to extract the last 32 bytes from the buffer.
+    uint8_t key[p256dhPublicKeyLength + p256dhPrivateKeyLength];
+    size_t keyLength = sizeof(key);
+    status = CCECCryptorExportKey(kCCImportKeyBinary, key, &keyLength, ccECKeyPrivate, ccPrivateKey);
+    RELEASE_ASSERT(status == kCCSuccess && keyLength == sizeof(key));
+
+    return P256DHKeyPair {
+        Vector<uint8_t> { publicKey, p256dhPublicKeyLength },
+        Vector<uint8_t> { key + p256dhPublicKeyLength, p256dhPrivateKeyLength }
+    };
+}
+
+bool validateP256DHPublicKey(Span<const uint8_t> publicKey)
+{
+    CCECCryptorRef ccPublicKey = nullptr;
+    CCCryptorStatus status = CCECCryptorImportKey(kCCImportKeyBinary, publicKey.data(), publicKey.size(), ccECKeyPublic, &ccPublicKey);
+    if (!ccPublicKey)
+        return false;
+    CCECCryptorRelease(ccPublicKey);
+    return status == kCCSuccess;
+}
+
+std::optional<Vector<uint8_t>> computeP256DHSharedSecret(Span<const uint8_t> publicKey, const P256DHKeyPair& keyPair)
+{
+    if (publicKey.size() != p256dhPublicKeyLength || keyPair.publicKey.size() != p256dhPublicKeyLength || keyPair.privateKey.size() != p256dhPrivateKeyLength)
+        return std::nullopt;
+
+    CCECCryptorRef ccPublicKey = nullptr;
+    CCECCryptorRef ccPrivateKey = nullptr;
+    auto releaser = WTF::makeScopeExit([&ccPublicKey, &ccPrivateKey]() {
+        if (ccPublicKey)
+            CCECCryptorRelease(ccPublicKey);
+        if (ccPrivateKey)
+            CCECCryptorRelease(ccPrivateKey);
+    });
+
+    if (CCECCryptorImportKey(kCCImportKeyBinary, publicKey.data(), p256dhPublicKeyLength, ccECKeyPublic, &ccPublicKey) != kCCSuccess)
+        return std::nullopt;
+
+    // CommonCrypto expects the binary format to be 65 byte public key followed by the 32 byte private key.
+    uint8_t keyBuf[p256dhPublicKeyLength + p256dhPrivateKeyLength];
+    memcpy(keyBuf, keyPair.publicKey.data(), p256dhPublicKeyLength);
+    memcpy(keyBuf + p256dhPublicKeyLength, keyPair.privateKey.data(), p256dhPrivateKeyLength);
+    if (CCECCryptorImportKey(kCCImportKeyBinary, keyBuf, sizeof(keyBuf), ccECKeyPrivate, &ccPrivateKey) != kCCSuccess)
+        return std::nullopt;
+
+    Vector<uint8_t> sharedSecret(p256dhSharedSecretLength);
+    size_t sharedSecretLength = sharedSecret.size();
+    if (CCECCryptorComputeSharedSecret(ccPrivateKey, ccPublicKey, sharedSecret.begin(), &sharedSecretLength) != kCCSuccess || sharedSecretLength != p256dhSharedSecretLength)
+        return std::nullopt;
+
+    return sharedSecret;
+}
+
+Vector<uint8_t> hmacSHA256(Span<const uint8_t> key, Span<const uint8_t> message)
+{
+    Vector<uint8_t> result(sha256DigestLength);
+    CCHmac(kCCHmacAlgSHA256, key.data(), key.size(), message.data(), message.size(), result.begin());
+    return result;
+}
+
+std::optional<Vector<uint8_t>> decryptAES128GCM(Span<const uint8_t> key, Span<const uint8_t> iv, Span<const uint8_t> cipherTextWithTag)
+{
+    if (cipherTextWithTag.size() < aes128GCMTagLength)
+        return std::nullopt;
+
+    Vector<uint8_t> plainText(cipherTextWithTag.size() - aes128GCMTagLength);
+    auto result = CCCryptorGCMOneshotDecrypt(kCCAlgorithmAES, key.data(), key.size(), iv.data(), iv.size(), nullptr /* additionalData */, 0 /* additionalDataLength */, cipherTextWithTag.data(), cipherTextWithTag.size() - aes128GCMTagLength, plainText.data(), cipherTextWithTag.end() - aes128GCMTagLength, aes128GCMTagLength);
+    if (result != kCCSuccess)
+        return std::nullopt;
+
+    return plainText;
+}
+
+} // namespace WebCore::PushCrypto
+
+#endif // ENABLE(SERVICE_WORKER)

Modified: trunk/Source/WebCore/PAL/ChangeLog (287014 => 287015)


--- trunk/Source/WebCore/PAL/ChangeLog	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/PAL/ChangeLog	2021-12-14 08:18:02 UTC (rev 287015)
@@ -1,3 +1,12 @@
+2021-12-14  Ben Nham  <[email protected]>
+
+        Add web push message decryption routines
+        https://bugs.webkit.org/show_bug.cgi?id=233903
+
+        Reviewed by Brady Eidson.
+
+        * pal/spi/cocoa/CommonCryptoSPI.h: Add AES-GCM decryption SPI.
+
 2021-12-11  Commit Queue  <[email protected]>
 
         Unreviewed, reverting r286893.

Modified: trunk/Source/WebCore/PAL/pal/spi/cocoa/CommonCryptoSPI.h (287014 => 287015)


--- trunk/Source/WebCore/PAL/pal/spi/cocoa/CommonCryptoSPI.h	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/PAL/pal/spi/cocoa/CommonCryptoSPI.h	2021-12-14 08:18:02 UTC (rev 287015)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include <CommonCrypto/CommonCrypto.h>
+
 #if USE(APPLE_INTERNAL_SDK)
 
 #include <CommonCrypto/CommonCryptorSPI.h>
@@ -118,6 +120,7 @@
 extern "C" CCStatus CCKDFParametersCreateHkdf(CCKDFParametersRef *params, const void *salt, size_t saltLen, const void *context, size_t contextLen);
 extern "C" void CCKDFParametersDestroy(CCKDFParametersRef params);
 extern "C" CCCryptorStatus CCCryptorGCM(CCOperation op, CCAlgorithm alg, const void* key, size_t keyLength, const void* iv, size_t ivLen, const void* aData, size_t aDataLen, const void* dataIn, size_t dataInLength, void* dataOut, void* tag, size_t* tagLength);
+extern "C" CCCryptorStatus CCCryptorGCMOneshotDecrypt(CCAlgorithm alg, const void *key, size_t keyLength, const void  *iv, size_t ivLen, const void  *aData, size_t aDataLen, const void *dataIn, size_t dataInLength, void        *dataOut, const void  *tagIn, size_t tagLength);
 extern "C" CCCryptorStatus CCRSACryptorCreateFromData(CCRSAKeyType keyType, const uint8_t *modulus, size_t modulusLength, const uint8_t *exponent, size_t exponentLength, const uint8_t *p, size_t pLength, const uint8_t *q, size_t qLength, CCRSACryptorRef *ref);
 
 #endif // !USE(APPLE_INTERNAL_SDK)

Modified: trunk/Source/WebCore/Sources.txt (287014 => 287015)


--- trunk/Source/WebCore/Sources.txt	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/Sources.txt	2021-12-14 08:18:02 UTC (rev 287015)
@@ -257,7 +257,9 @@
 Modules/pictureinpicture/EnterPictureInPictureEvent.cpp
 Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp
 Modules/pictureinpicture/PictureInPictureWindow.cpp
+Modules/push-api/PushCrypto.cpp
 Modules/push-api/PushEvent.cpp
+Modules/push-api/PushMessageCrypto.cpp
 Modules/push-api/PushMessageData.cpp
 Modules/push-api/PushSubscription.cpp
 Modules/push-api/PushSubscriptionChangeEvent.cpp

Modified: trunk/Source/WebCore/SourcesCocoa.txt (287014 => 287015)


--- trunk/Source/WebCore/SourcesCocoa.txt	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/SourcesCocoa.txt	2021-12-14 08:18:02 UTC (rev 287015)
@@ -106,6 +106,7 @@
 Modules/model-element/scenekit/SceneKitModelLoaderClient.mm
 Modules/model-element/scenekit/SceneKitModelLoaderUSD.mm
 Modules/model-element/scenekit/SceneKitModelPlayer.mm
+Modules/push-api/cocoa/PushCryptoCocoa.cpp
 Modules/speech/cocoa/SpeechRecognizerCocoa.mm
 Modules/speech/cocoa/WebSpeechRecognizerTask.mm
 Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (287014 => 287015)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-14 08:12:55 UTC (rev 287014)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-14 08:18:02 UTC (rev 287015)
@@ -5436,6 +5436,8 @@
 		EB28ED442717AC11005F0393 /* PushSubscriptionData.h in Headers */ = {isa = PBXBuildFile; fileRef = EB28ED412717ABA9005F0393 /* PushSubscriptionData.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EB3C29B62729C38800FB65B4 /* PushSubscriptionChangeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3C29B42729C36E00FB65B4 /* PushSubscriptionChangeEvent.h */; };
 		EB3C29B72729C38C00FB65B4 /* PushSubscriptionChangeEventInit.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3C29B12729C36D00FB65B4 /* PushSubscriptionChangeEventInit.h */; };
+		EBA75C46275EC61A00D6D31C /* PushCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA75C42275EBDAB00D6D31C /* PushCrypto.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		EBA75C47275EC62100D6D31C /* PushMessageCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA75C40275EBDAA00D6D31C /* PushMessageCrypto.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EBB9738127100671007732EF /* PushManager.h in Headers */ = {isa = PBXBuildFile; fileRef = EBB9738027100654007732EF /* PushManager.h */; };
 		EBB9738227100676007732EF /* PushPermissionState.h in Headers */ = {isa = PBXBuildFile; fileRef = EBB9737827100651007732EF /* PushPermissionState.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EBB9738327100684007732EF /* ServiceWorkerRegistrationPushAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = EBB9737A27100652007732EF /* ServiceWorkerRegistrationPushAPI.h */; };
@@ -17581,6 +17583,11 @@
 		EB3C29B22729C36E00FB65B4 /* PushSubscriptionChangeEventInit.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PushSubscriptionChangeEventInit.idl; sourceTree = "<group>"; };
 		EB3C29B32729C36E00FB65B4 /* PushSubscriptionChangeEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PushSubscriptionChangeEvent.idl; sourceTree = "<group>"; };
 		EB3C29B42729C36E00FB65B4 /* PushSubscriptionChangeEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushSubscriptionChangeEvent.h; sourceTree = "<group>"; };
+		EBA75C3E275EBDAA00D6D31C /* PushMessageCrypto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PushMessageCrypto.cpp; sourceTree = "<group>"; };
+		EBA75C40275EBDAA00D6D31C /* PushMessageCrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PushMessageCrypto.h; sourceTree = "<group>"; };
+		EBA75C41275EBDAB00D6D31C /* PushCrypto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PushCrypto.cpp; sourceTree = "<group>"; };
+		EBA75C42275EBDAB00D6D31C /* PushCrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PushCrypto.h; sourceTree = "<group>"; };
+		EBA75C45275EC58E00D6D31C /* PushCryptoCocoa.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PushCryptoCocoa.cpp; sourceTree = "<group>"; };
 		EBB9737827100651007732EF /* PushPermissionState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PushPermissionState.h; sourceTree = "<group>"; };
 		EBB9737A27100652007732EF /* ServiceWorkerRegistrationPushAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ServiceWorkerRegistrationPushAPI.h; sourceTree = "<group>"; };
 		EBB9737B27100652007732EF /* ServiceWorkerRegistration+PushAPI.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "ServiceWorkerRegistration+PushAPI.idl"; sourceTree = "<group>"; };
@@ -21034,6 +21041,9 @@
 		418FCBB82706E4BD00F96ECA /* push-api */ = {
 			isa = PBXGroup;
 			children = (
+				EBA75C44275EC56000D6D31C /* cocoa */,
+				EBA75C41275EBDAB00D6D31C /* PushCrypto.cpp */,
+				EBA75C42275EBDAB00D6D31C /* PushCrypto.h */,
 				EB0FB6FD270D0AE800F7810D /* PushEncryptionKeyName.h */,
 				EB0FB700270D0AEA00F7810D /* PushEncryptionKeyName.idl */,
 				418FCBBB2706E4F600F96ECA /* PushEvent.cpp */,
@@ -21044,6 +21054,8 @@
 				EBB9737C27100652007732EF /* PushManager.cpp */,
 				EBB9738027100654007732EF /* PushManager.h */,
 				EBB9737E27100653007732EF /* PushManager.idl */,
+				EBA75C3E275EBDAA00D6D31C /* PushMessageCrypto.cpp */,
+				EBA75C40275EBDAA00D6D31C /* PushMessageCrypto.h */,
 				418FCBBE2706E4F700F96ECA /* PushMessageData.cpp */,
 				418FCBBC2706E4F600F96ECA /* PushMessageData.h */,
 				418FCBBA2706E4F500F96ECA /* PushMessageData.idl */,
@@ -31231,6 +31243,14 @@
 			path = "contact-picker";
 			sourceTree = "<group>";
 		};
+		EBA75C44275EC56000D6D31C /* cocoa */ = {
+			isa = PBXGroup;
+			children = (
+				EBA75C45275EC58E00D6D31C /* PushCryptoCocoa.cpp */,
+			);
+			path = cocoa;
+			sourceTree = "<group>";
+		};
 		ED501DC90B249F3900AE18D9 /* mac */ = {
 			isa = PBXGroup;
 			children = (
@@ -36424,10 +36444,12 @@
 				57303BEB20097F4000355965 /* PublicKeyCredentialType.h in Headers */,
 				0081FF0016B0A2D3008AAA7A /* PublicSuffix.h in Headers */,
 				10FB084B14E15C7E00A3DB98 /* PublicURLManager.h in Headers */,
+				EBA75C46275EC61A00D6D31C /* PushCrypto.h in Headers */,
 				EB0FB708270D0B1000F7810D /* PushEncryptionKeyName.h in Headers */,
 				418FCBC12706E4FB00F96ECA /* PushEvent.h in Headers */,
 				418FCBC22706E50100F96ECA /* PushEventInit.h in Headers */,
 				EBB9738127100671007732EF /* PushManager.h in Headers */,
+				EBA75C47275EC62100D6D31C /* PushMessageCrypto.h in Headers */,
 				EBB9738227100676007732EF /* PushPermissionState.h in Headers */,
 				83D511F6250C1CBF002EDC51 /* PushPullFIFO.h in Headers */,
 				EB0FB709270D0B1800F7810D /* PushSubscription.h in Headers */,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to