1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 * Copyright (C) 2017 Metrological Group B.V.
4 * Copyright (C) 2017 Igalia S.L.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#include "CryptoAlgorithmECDH.h"
30
31#if ENABLE(WEB_CRYPTO)
32
33#include "CryptoKeyEC.h"
34#include "GCryptUtilities.h"
35#include <pal/crypto/gcrypt/Handle.h>
36#include <pal/crypto/gcrypt/Utilities.h>
37
38namespace WebCore {
39
40static Optional<Vector<uint8_t>> gcryptDerive(gcry_sexp_t baseKeySexp, gcry_sexp_t publicKeySexp, size_t keySizeInBytes)
41{
42 // First, retrieve private key data, which is roughly of the following form:
43 // (private-key
44 // (ecc
45 // ...
46 // (d ...)))
47 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
48 {
49 PAL::GCrypt::Handle<gcry_sexp_t> dSexp(gcry_sexp_find_token(baseKeySexp, "d", 0));
50 if (!dSexp)
51 return WTF::nullopt;
52
53 auto data = mpiData(dSexp);
54 if (!data)
55 return WTF::nullopt;
56
57 gcry_sexp_build(&dataSexp, nullptr, "(data(flags raw)(value %b))", data->size(), data->data());
58 if (!dataSexp)
59 return WTF::nullopt;
60 }
61
62 // Encrypt the data s-expression with the public key.
63 PAL::GCrypt::Handle<gcry_sexp_t> cipherSexp;
64 gcry_error_t error = gcry_pk_encrypt(&cipherSexp, dataSexp, publicKeySexp);
65 if (error != GPG_ERR_NO_ERROR) {
66 PAL::GCrypt::logError(error);
67 return WTF::nullopt;
68 }
69
70 // Retrieve the shared point value from the generated s-expression, which is of the following form:
71 // (enc-val
72 // (ecdh
73 // (s ...)
74 // (e ...)))
75 PAL::GCrypt::Handle<gcry_mpi_t> xMPI(gcry_mpi_new(0));
76 if (!xMPI)
77 return WTF::nullopt;
78
79 {
80 PAL::GCrypt::Handle<gcry_sexp_t> sSexp(gcry_sexp_find_token(cipherSexp, "s", 0));
81 if (!sSexp)
82 return WTF::nullopt;
83
84 PAL::GCrypt::Handle<gcry_mpi_t> sMPI(gcry_sexp_nth_mpi(sSexp, 1, GCRYMPI_FMT_USG));
85 if (!sMPI)
86 return WTF::nullopt;
87
88 PAL::GCrypt::Handle<gcry_mpi_point_t> point(gcry_mpi_point_new(0));
89 if (!point)
90 return WTF::nullopt;
91
92 error = gcry_mpi_ec_decode_point(point, sMPI, nullptr);
93 if (error != GPG_ERR_NO_ERROR)
94 return WTF::nullopt;
95
96 // We're only interested in the x-coordinate.
97 gcry_mpi_point_snatch_get(xMPI, nullptr, nullptr, point.release());
98 }
99
100 return mpiZeroPrefixedData(xMPI, keySizeInBytes);
101}
102
103Optional<Vector<uint8_t>> CryptoAlgorithmECDH::platformDeriveBits(const CryptoKeyEC& baseKey, const CryptoKeyEC& publicKey)
104{
105 return gcryptDerive(baseKey.platformKey(), publicKey.platformKey(), (baseKey.keySizeInBits() + 7) / 8);
106}
107
108} // namespace WebCore
109
110#endif // ENABLE(WEB_CRYPTO)
111