// Copyright (c) 2017-2022 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 #pragma once // WebCrypto API #include #include #include #include #include // for EVP_MD_CTX, X509 #include namespace workerd::api { namespace node { class CryptoImpl; } namespace { class EdDsaKey; class EllipticKey; } // namespace // Subset of recognized key usage values. // // https://w3c.github.io/webcrypto/#dfn-RecognizedKeyUsage class CryptoKeyUsageSet { public: static constexpr CryptoKeyUsageSet encrypt() { return 1 << 0; } static constexpr CryptoKeyUsageSet decrypt() { return 1 << 1; } static constexpr CryptoKeyUsageSet sign() { return 1 << 2; } static constexpr CryptoKeyUsageSet verify() { return 1 << 3; } static constexpr CryptoKeyUsageSet deriveKey() { return 1 << 4; } static constexpr CryptoKeyUsageSet deriveBits() { return 1 << 5; } static constexpr CryptoKeyUsageSet wrapKey() { return 1 << 6; } static constexpr CryptoKeyUsageSet unwrapKey() { return 1 << 7; } static constexpr CryptoKeyUsageSet publicKeyMask() { return encrypt() | verify() | wrapKey(); } static constexpr CryptoKeyUsageSet privateKeyMask() { return decrypt() | sign() | unwrapKey() | deriveKey() | deriveBits(); } static constexpr CryptoKeyUsageSet derivationKeyMask() { return deriveKey() | deriveBits(); } CryptoKeyUsageSet(): set(0) {} CryptoKeyUsageSet operator&(CryptoKeyUsageSet other) const { return set & other.set; } CryptoKeyUsageSet operator|(CryptoKeyUsageSet other) const { return set | other.set; } CryptoKeyUsageSet& operator&=(CryptoKeyUsageSet other) { set &= other.set; return *this; } CryptoKeyUsageSet& operator|=(CryptoKeyUsageSet other) { set |= other.set; return *this; } // True if and only if this is a subset of the given set. inline bool operator<=(CryptoKeyUsageSet superset) const { return (superset & *this) == *this; } inline bool operator==(CryptoKeyUsageSet other) const { return set == other.set; } unsigned int size() const { return std::popcount(set); } bool isSingleton() const { return size() == 1; } // The recognized name. This must be a singleton. kj::StringPtr name() const; // A singleton with the given name. static CryptoKeyUsageSet byName(kj::StringPtr name); // All singletons, in the order defined by the spec (encrypt, decrypt, sign, verify, ...). static kj::ArrayPtr singletons(); enum class Context { generate, importSecret, importPublic, importPrivate }; // Parses a list of key usage strings. Throws if any are not recognized or not in mask. static CryptoKeyUsageSet validate(kj::StringPtr normalizedName, Context ctx, kj::ArrayPtr actual, CryptoKeyUsageSet mask); template auto map(Func f) const -> kj::Array { auto strings = kj::heapArrayBuilder(size()); for (auto& singleton: singletons()) { if (singleton <= *this) strings.add(f(singleton)); } return strings.finish(); } private: constexpr CryptoKeyUsageSet(uint8_t set): set(set) {} uint8_t set; }; // ======================================================================================= // SubtleCrypto and CryptoKey // Represents keying material. Users get an object of this type by calling SubtleCrypto's // `importKey()`, `generateKey()`, or `deriveKey()` methods. The user can then use the object by // passing it as a parameter to other SubtleCrypto methods. class CryptoKey: public jsg::Object { public: // KeyAlgorithm dictionaries // // These dictionaries implement CryptoKey's `algorithm` property. They allow user code to inspect // which algorithm a particular CryptoKey is used for, and what algorithm-specific parameters it // might have. These are similar to the Algorithm-derived dictionaries used as parameters to // SubtleCrypto's interface (see the SubtleCrypto class below), but they are specific to // CryptoKey. Like Algorithm, all of these dictionaries notionally derive from a KeyAlgorithm base // class. // // One difference between CryptoKey::KeyAlgorithm dictionaries and SubtleCrypto::Algorithm // dictionaries is that KeyAlgorithms use a kj::StringPtr to store their algorithm names, because // we know that they will only ever point to internal static strings of normalized algorithm // names. struct KeyAlgorithm { kj::StringPtr name; JSG_STRUCT(name); JSG_MEMORY_INFO(KeyAlgorithm) {} }; struct AesKeyAlgorithm { // "AES-CTR", "AES-GCM", "AES-CBC", "AES-KW" kj::StringPtr name; // Length in bits of the key. uint16_t length; JSG_STRUCT(name, length); JSG_MEMORY_INFO(AesKeyAlgorithm) {} }; struct HmacKeyAlgorithm { // "HMAC" kj::StringPtr name; // The inner hash function to use. KeyAlgorithm hash; // Length in bits of the key. The spec wants this to be an unsigned long, but whatever. // TODO(someday): Reexamine use of uint16_t in these algorithm structures. // We picked uint16_t to work around ambiguous bindings for uint32_t in // jsg::PrimitiveWrapper::wrap(). HMAC, at least, allows very long keys. uint16_t length; JSG_STRUCT(name, hash, length); JSG_MEMORY_INFO(HmacKeyAlgorithm) {} }; struct RsaKeyAlgorithm { // "RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP" kj::StringPtr name; // The length, in bits, of the RSA modulus. The spec would have this be an unsigned long. uint16_t modulusLength; // The RSA public exponent (in unsigned big-endian form) jsg::JsRef publicExponent; // The hash algorithm that is used with this key. jsg::Optional hash; RsaKeyAlgorithm clone(jsg::Lock& js) const { auto pe = publicExponent.getHandle(js); auto data = pe.asArrayPtr(); // Should only happen if the flag is enabled and an algorithm field is cloned twice. if (FeatureFlags::get(js).getCryptoPreservePublicExponent()) { auto exp = jsg::JsUint8Array::create(js, data); return {name, modulusLength, jsg::JsBufferSource(exp).addRef(js), hash}; } else { auto exp = jsg::JsArrayBuffer::create(js, data); return {name, modulusLength, jsg::JsBufferSource(exp).addRef(js), hash}; } } JSG_STRUCT(name, modulusLength, publicExponent, hash); JSG_MEMORY_INFO(RsaKeyAlgorithm) {} }; struct EllipticKeyAlgorithm { // "ECDSA" or "ECDH" kj::StringPtr name; // "P-256", "P-384", or "P-521" kj::StringPtr namedCurve; JSG_STRUCT(name, namedCurve); JSG_MEMORY_INFO(EllipticKeyAlgorithm) {} }; // Catch-all that can be used for extension algorithms. Combines fields of several known types. struct ArbitraryKeyAlgorithm { // TODO(cleanup): Should we just replace AlgorithmVariant with this? Note we'd have to add // `publicExponent` which is currently a problem because it makes the type non-copyable... // Alternatively, should we create some better way to abstract this? kj::StringPtr name; jsg::Optional hash; jsg::Optional namedCurve; jsg::Optional length; JSG_STRUCT(name, hash, namedCurve, length); }; // Used as part of the Node.js crypto implementation of KeyObject. // Defined here instead of api/node/crypto.h because it it is needed // by CryptoKey::Impl to provide the actual implementation. struct AsymmetricKeyDetails { jsg::Optional modulusLength; jsg::Optional> publicExponent; // TODO(later): BoringSSL does not currently support getting the RSA-PSS // details for an RSA key. Once it does, we can update our impl and add // these fields. // jsg::Optional hashAlgorithm; // jsg::Optional mgf1HashAlgorithm; // jsg::Optional saltLength; jsg::Optional divisorLength; jsg::Optional namedCurve; JSG_STRUCT(modulusLength, publicExponent, // hashAlgorithm, // mgf1HashAlgorithm, // saltLength, divisorLength, namedCurve); }; AsymmetricKeyDetails getAsymmetricKeyDetails(jsg::Lock& js) const; ~CryptoKey() noexcept(false); // Returns the name of this CryptoKey's algorithm in a normalized, statically-allocated string. kj::StringPtr getAlgorithmName() const; // JS API using AlgorithmVariant = kj::OneOf; AlgorithmVariant getAlgorithm(jsg::Lock& js) const; kj::StringPtr getType() const; bool getExtractable() const; kj::Array getUsages() const; CryptoKeyUsageSet getUsageSet() const; JSG_RESOURCE_TYPE(CryptoKey) { JSG_READONLY_INSTANCE_PROPERTY(type, getType); JSG_READONLY_INSTANCE_PROPERTY(extractable, getExtractable); JSG_READONLY_INSTANCE_PROPERTY(algorithm, getAlgorithm); JSG_READONLY_INSTANCE_PROPERTY(usages, getUsages); } // HACK: Needs to be public so derived classes can inherit from it. class Impl; // Treat as private -- needs to be public for js.alloc()... explicit CryptoKey(kj::Own impl); // Compare the contents of this key with the other. Will return false if // either key is not extractable or if the keys are a different type. // For secret keys, we will compare only the actual key material and not // the algorithm parameters or the algorithm name. We will also ensure // that a timing-safe comparison is used for the key material. bool operator==(const CryptoKey& other) const; void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; bool verifyX509Public(const X509* x509) const; bool verifyX509Private(const X509* x509) const; private: kj::Own impl; void visitForGc(jsg::GcVisitor& visitor); friend class SubtleCrypto; friend class EllipticKey; friend class EdDsaKey; friend class node::CryptoImpl; }; struct CryptoKeyPair { jsg::Ref publicKey; jsg::Ref privateKey; JSG_STRUCT(publicKey, privateKey); }; class SubtleCrypto: public jsg::Object { public: // Algorithm dictionaries // // Every method of SubtleCrypto except `exportKey()` takes an `algorithm` parameter, usually as the // first argument. This can usually be a raw string algorithm name, or an object with a `name` // field and other fields. The other fields differ based on which algorithm is named and which // function is being called. We achieve polymorphism here by making all the fields except `name` // be `jsg::Optional`... ugly, but it works. // Type of the `algorithm` parameter passed to `digest()`. Also used as the type of the `hash` // parameter of many other algorithm structs. struct HashAlgorithm { kj::String name; JSG_STRUCT(name); }; // Type of the `algorithm` parameter passed to `encrypt()` and `decrypt()`. Different // algorithms call for different fields. struct EncryptAlgorithm { // E.g. "AES-GCM" kj::String name; // For AES: The initialization vector use. May be up to 2^64-1 bytes long. jsg::Optional> iv; // The additional authentication data to include. jsg::Optional> additionalData; // The desired length of the authentication tag. May be 0 - 128. // Note: the spec specifies this as a Web IDL byte (== signed char in C++), not an int, but JS // has no such 8-bit integer animal. jsg::Optional tagLength; // The initial value of the counter block for AES-CTR. // https://www.w3.org/TR/WebCryptoAPI/#aes-ctr-params jsg::Optional> counter; // The length, in bits, of the rightmost part of the counter block that is incremented. // See above why we use int instead of int8_t. // https://www.w3.org/TR/WebCryptoAPI/#aes-ctr-params jsg::Optional length; // The optional label/application data to associate with the message (for RSA-OAEP) jsg::Optional> label; JSG_STRUCT(name, iv, additionalData, tagLength, counter, length, label); }; // Type of the `algorithm` parameter passed to `sign()` and `verify()`. Different // algorithms call for different fields. struct SignAlgorithm { // E.g. "RSASSA-PKCS1-v1_5", "ECDSA" kj::String name; // ECDSA wants the hash to be specified at call time rather than import // time. jsg::Optional> hash; // Not part of the WebCrypto spec. Used by an extension. jsg::Optional dataLength; // Used for RSA-PSS jsg::Optional saltLength; JSG_STRUCT(name, hash, dataLength, saltLength); }; // Type of the `algorithm` parameter passed to `generateKey()`. Different algorithms call for // different fields. struct GenerateKeyAlgorithm { // E.g. "HMAC", "RSASSA-PKCS1-v1_5", "ECDSA", ... kj::String name; // For signing algorithms where the hash is specified at import time, identifies the hash // function to use, e.g. "SHA-256". jsg::Optional> hash; // For RSA algorithms: The length in bits of the RSA modulus. jsg::Optional modulusLength; // For RSA algorithms jsg::Optional> publicExponent; // For AES algorithms or when name == "HMAC": The length in bits of the key. jsg::Optional length; // When name == "ECDSA": "P-256", "P-384", or "P-521" jsg::Optional namedCurve; JSG_STRUCT(name, hash, modulusLength, publicExponent, length, namedCurve); }; // Type of the `algorithm` parameter passed to `importKey()`, as well as the // `derivedKeyAlgorithm` parameter to `deriveKey()`. Different algorithms call for different // fields. struct ImportKeyAlgorithm { // E.g. "HMAC", "RSASSA-PKCS1-v1_5", "ECDSA", ... kj::String name; // For signing algorithms where the hash is specified at import time, identifies the hash // function to use, e.g. "SHA-256". jsg::Optional> hash; // When name == "HMAC": The length in bits of the key. jsg::Optional length; // When name == "ECDSA": "P-256", "P-384", or "P-521" jsg::Optional namedCurve; // Not part of the WebCrypto spec. Used by an extension to indicate that curve points are in // compressed format. (The standard algorithms do not recognize this option.) jsg::Optional compressed; JSG_STRUCT(name, hash, length, namedCurve, compressed); }; // Type of the `algorithm` parameter passed to `deriveKey()`. Different algorithms call for // different fields. struct DeriveKeyAlgorithm { // e.g. "PBKDF2", "ECDH", etc kj::String name; // PBKDF2 parameters jsg::Optional> salt; jsg::Optional iterations; jsg::Optional> hash; // ECDH parameters jsg::Optional> $public; // HKDF parameters (some shared with PBKDF2) // Bit string that corresponds to the context and application specific context for the derived // keying material jsg::Optional> info; JSG_STRUCT(name, salt, iterations, hash, $public, info); }; // https://www.w3.org/TR/WebCryptoAPI/#JsonWebKey-dictionary struct JsonWebKey { struct RsaOtherPrimesInfo { // The following fields are defined in Section 6.3.2.7 of JSON Web Algorithms jsg::Optional r; jsg::Optional d; jsg::Optional t; JSG_STRUCT(r, d, t); JSG_STRUCT_TS_OVERRIDE(RsaOtherPrimesInfo); // Rename from SubtleCryptoJsonWebKeyRsaOtherPrimesInfo }; // The following fields are defined in Section 3.1 of JSON Web Key (RFC 7517). // NOTE: The Web Crypto spec's IDL for JsonWebKey considers `kty` optional, yet the RFC lists it // as required. kj::String kty; jsg::Optional use; jsg::Optional> key_ops; jsg::Optional alg; // The following fields are defined in JSON Web Key Parameters Registration jsg::Optional ext; // The following fields are defined in Section 6 of JSON Web Algorithms jsg::Optional crv; jsg::Optional x; jsg::Optional y; jsg::Optional d; jsg::Optional n; jsg::Optional e; jsg::Optional p; jsg::Optional q; jsg::Optional dp; jsg::Optional dq; jsg::Optional qi; jsg::Optional> oth; // TODO(conform): Support multiprime RSA keys. This used to be jsg::Unimplemented but needs to // be properly defined for exporting JWK of other keys. On the other hand, are we even going // to bother adding support for multiprime RSA keys? Chromium doesn't AFAICT... jsg::Optional k; JSG_STRUCT(kty, use, key_ops, alg, ext, crv, x, y, d, n, e, p, q, dp, dq, qi, oth, k); JSG_STRUCT_TS_OVERRIDE(JsonWebKey); // Rename from SubtleCryptoJsonWebKey }; using ImportKeyData = kj::OneOf, JsonWebKey>; using ExportKeyData = kj::OneOf, JsonWebKey>; jsg::Promise> encrypt(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array plainText); jsg::Promise> decrypt(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array cipherText); jsg::Promise> sign(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array data); jsg::Promise verify(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array signature, kj::Array data); jsg::Promise> digest(jsg::Lock& js, kj::OneOf algorithm, kj::Array data); jsg::Promise, CryptoKeyPair>> generateKey(jsg::Lock& js, kj::OneOf algorithm, bool extractable, kj::Array keyUsages); jsg::Promise> deriveKey(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& baseKey, kj::OneOf derivedKeyAlgorithm, bool extractable, kj::Array keyUsages); jsg::Promise> deriveBits(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& baseKey, // The operation needs to be able to take both undefined and null // and handle them equivalently... if we just used jsg::Optional // here, null would be coerced to 0. If we just used kj::Maybe // here, undefined would be an error. So we need to use an optional // maybe int in order to treat undefined and null as being equivalent. jsg::Optional> length); jsg::Promise> importKey(jsg::Lock& js, kj::String format, ImportKeyData keyData, kj::OneOf algorithm, bool extractable, kj::Array keyUsages); // NOT VISIBLE TO JS: like importKey() but return the key, not a promise. jsg::Ref importKeySync(jsg::Lock& js, kj::StringPtr format, ImportKeyData keyData, ImportKeyAlgorithm algorithm, bool extractable, kj::ArrayPtr keyUsages); jsg::Promise exportKey(jsg::Lock& js, kj::String format, const CryptoKey& key); jsg::Promise> wrapKey(jsg::Lock& js, kj::String format, const CryptoKey& key, const CryptoKey& wrappingKey, kj::OneOf wrapAlgorithm, const jsg::TypeHandler& jwkHandler); jsg::Promise> unwrapKey(jsg::Lock& js, kj::String format, kj::Array wrappedKey, const CryptoKey& unwrappingKey, kj::OneOf unwrapAlgorithm, kj::OneOf unwrappedKeyAlgorithm, bool extractable, kj::Array keyUsages, const jsg::TypeHandler& jwkHandler); // This is a non-standard extension based off Node.js' implementation of crypto.timingSafeEqual. bool timingSafeEqual(jsg::JsBufferSource a, jsg::JsBufferSource b); JSG_RESOURCE_TYPE(SubtleCrypto) { JSG_METHOD(encrypt); JSG_METHOD(decrypt); JSG_METHOD(sign); JSG_METHOD(verify); JSG_METHOD(digest); JSG_METHOD(generateKey); JSG_METHOD(deriveKey); JSG_METHOD(deriveBits); JSG_METHOD(importKey); JSG_METHOD(exportKey); JSG_METHOD(wrapKey); JSG_METHOD(unwrapKey); JSG_METHOD(timingSafeEqual); JSG_TS_OVERRIDE({ wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm) : Promise; deriveBits(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey : CryptoKey, length? : number | null) : Promise; digest(algorithm: string | SubtleCryptoHashAlgorithm, data: ArrayBuffer | ArrayBufferView) : Promise; sign(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, data: ArrayBuffer | ArrayBufferView) : Promise; decrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, cipherText: ArrayBuffer | ArrayBufferView) : Promise; encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView) : Promise; exportKey(format: string, key: CryptoKey) : Promise; }); } }; // ======================================================================================= // DigestStream is a non-standard extension that provides a way of generating // a hash digest from streaming data. It combines Web Crypto concepts into a // WritableStream and is compatible with both APIs. class DigestContext { public: virtual ~DigestContext() noexcept = default; virtual void write(kj::ArrayPtr buffer) = 0; virtual jsg::JsArrayBuffer close(jsg::Lock& js) = 0; }; class DigestStream: public WritableStream { public: using DigestContextPtr = kj::Own; using Algorithm = kj::OneOf; explicit DigestStream(kj::Own controller, SubtleCrypto::HashAlgorithm algorithm, jsg::Promise>::Resolver resolver, jsg::Promise> promise); static jsg::Ref constructor(jsg::Lock& js, Algorithm algorithm); jsg::MemoizedIdentity>>& getDigest() { return promise; } void dispose(jsg::Lock& js); uint64_t getBytesWritten() const { return bytesWritten; } JSG_RESOURCE_TYPE(DigestStream, CompatibilityFlags::Reader flags) { JSG_INHERIT(WritableStream); if (flags.getJsgPropertyOnPrototypeTemplate()) { JSG_READONLY_PROTOTYPE_PROPERTY(digest, getDigest); } else { JSG_READONLY_INSTANCE_PROPERTY(digest, getDigest); } JSG_READONLY_PROTOTYPE_PROPERTY(bytesWritten, getBytesWritten); JSG_DISPOSE(dispose); JSG_TS_OVERRIDE(extends WritableStream { readonly digest: Promise; }); } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; private: static DigestContextPtr initContext(SubtleCrypto::HashAlgorithm& algorithm); struct Ready { SubtleCrypto::HashAlgorithm algorithm; jsg::Promise>::Resolver resolver; DigestContextPtr context; Ready(SubtleCrypto::HashAlgorithm algorithm, jsg::Promise>::Resolver resolver) : algorithm(kj::mv(algorithm)), resolver(kj::mv(resolver)), context(initContext(this->algorithm)) {} }; jsg::MemoizedIdentity>> promise; kj::OneOf state; uint64_t bytesWritten = 0; kj::Maybe write(jsg::Lock& js, kj::ArrayPtr buffer); kj::Maybe close(jsg::Lock& js); void abort(jsg::Lock& js, jsg::JsValue reason); void visitForGc(jsg::GcVisitor& visitor); }; // ======================================================================================= // Crypto // Implements the Crypto interface as prescribed by: // https://www.w3.org/TR/WebCryptoAPI/#crypto-interface class Crypto: public jsg::Object { public: Crypto(jsg::Lock& js): subtle(js.alloc()) {} jsg::JsArrayBufferView getRandomValues(jsg::JsArrayBufferView buffer); kj::String randomUUID(); jsg::Ref getSubtle() { return subtle.addRef(); } JSG_RESOURCE_TYPE(Crypto, CompatibilityFlags::Reader flags) { if (flags.getJsgPropertyOnPrototypeTemplate()) { JSG_READONLY_PROTOTYPE_PROPERTY(subtle, getSubtle); } else { JSG_READONLY_INSTANCE_PROPERTY(subtle, getSubtle); } JSG_METHOD(getRandomValues); JSG_METHOD(randomUUID); JSG_NESTED_TYPE(DigestStream); JSG_TS_OVERRIDE({ getRandomValues< T extends | Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array >(buffer: T): T; }); } void visitForGc(jsg::GcVisitor& visitor) { visitor.visit(subtle); } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("subtle", subtle); } private: jsg::Ref subtle; }; #define EW_CRYPTO_ISOLATE_TYPES \ api::Crypto, api::SubtleCrypto, api::CryptoKey, api::CryptoKeyPair, \ api::SubtleCrypto::JsonWebKey, api::SubtleCrypto::JsonWebKey::RsaOtherPrimesInfo, \ api::SubtleCrypto::DeriveKeyAlgorithm, api::SubtleCrypto::EncryptAlgorithm, \ api::SubtleCrypto::GenerateKeyAlgorithm, api::SubtleCrypto::HashAlgorithm, \ api::SubtleCrypto::ImportKeyAlgorithm, api::SubtleCrypto::SignAlgorithm, \ api::CryptoKey::KeyAlgorithm, api::CryptoKey::AesKeyAlgorithm, \ api::CryptoKey::HmacKeyAlgorithm, api::CryptoKey::RsaKeyAlgorithm, \ api::CryptoKey::EllipticKeyAlgorithm, api::CryptoKey::ArbitraryKeyAlgorithm, \ api::CryptoKey::AsymmetricKeyDetails, api::DigestStream } // namespace workerd::api KJ_DECLARE_NON_POLYMORPHIC(EVP_MD_CTX) KJ_DECLARE_NON_POLYMORPHIC(BIO);