@turnkey/crypto
Advanced tools
+254
| 'use strict'; | ||
| var encoding = require('@turnkey/encoding'); | ||
| var p256 = require('@noble/curves/p256'); | ||
| var sha2 = require('@noble/hashes/sha2'); | ||
| var CBOR = require('cbor-js'); | ||
| var x509 = require('@peculiar/x509'); | ||
| var constants = require('./constants.js'); | ||
| function _interopNamespaceDefault(e) { | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { return e[k]; } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| n.default = e; | ||
| return Object.freeze(n); | ||
| } | ||
| var CBOR__namespace = /*#__PURE__*/_interopNamespaceDefault(CBOR); | ||
| var x509__namespace = /*#__PURE__*/_interopNamespaceDefault(x509); | ||
| const getCryptoInstance = async () => { | ||
| let cryptoInstance; | ||
| // Use globalThis.crypto.subtle if available | ||
| if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) { | ||
| cryptoInstance = globalThis.crypto; | ||
| x509__namespace.cryptoProvider.set(cryptoInstance); | ||
| return cryptoInstance; | ||
| } | ||
| try { | ||
| // Dynamic import to prevent bundling in environments that already have WebCrypto | ||
| const { Crypto: PeculiarCrypto } = await import('@peculiar/webcrypto'); | ||
| cryptoInstance = new PeculiarCrypto(); | ||
| x509__namespace.cryptoProvider.set(cryptoInstance); | ||
| return cryptoInstance; | ||
| } | ||
| catch { | ||
| // Happens usually on React Native | ||
| throw new Error("No WebCrypto implementation found. " + | ||
| "In React Native, please polyfill `global.crypto.subtle` (e.g., with `react-native-webcrypto`) " + | ||
| "before calling verify()."); | ||
| } | ||
| }; | ||
| /** | ||
| * Utility: SHA-256 digest → hex (uppercase) | ||
| */ | ||
| async function sha256Hex(data) { | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| const digest = await cryptoInstance.subtle.digest("SHA-256", data); | ||
| return encoding.uint8ArrayToHexString(new Uint8Array(digest)).toUpperCase(); | ||
| } | ||
| /** | ||
| * Utility: Import SPKI public key for ECDSA verify | ||
| */ | ||
| async function importEcdsaPublicKey(spki) { | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| return cryptoInstance.subtle.importKey("spki", spki, { name: "ECDSA", namedCurve: "P-384" }, // AWS Nitro uses ES384 | ||
| false, ["verify"]); | ||
| } | ||
| /** | ||
| * verify goes through the following verification steps for an app proof & boot proof pair: | ||
| * - Verify app proof signature | ||
| * - Verify the boot proof | ||
| * - Attestation doc was signed by AWS | ||
| * - Attestation doc's `user_data` is the hash of the qos manifest | ||
| * - Verify the connection between the app proof & boot proof i.e. that the ephemeral keys match | ||
| * | ||
| * For more information, check out https://whitepaper.turnkey.com/foundations | ||
| */ | ||
| async function verify(appProof, bootProof) { | ||
| // 1. Verify App Proof | ||
| verifyAppProofSignature(appProof); | ||
| // 2. Verify Boot Proof | ||
| // Parse attestation | ||
| const coseSign1Der = Uint8Array.from(atob(bootProof.awsAttestationDocB64) | ||
| .split("") | ||
| .map((c) => c.charCodeAt(0))); | ||
| const coseSign1 = CBOR__namespace.decode(coseSign1Der.buffer); | ||
| const [, , payload] = coseSign1; | ||
| const attestationDoc = CBOR__namespace.decode(new Uint8Array(payload).buffer); | ||
| // Verify cose sign1 signature | ||
| await verifyCoseSign1Sig(coseSign1, attestationDoc.certificate); | ||
| // Verify certificate chain | ||
| const appProofTimestampMs = parseInt(JSON.parse(appProof.proofPayload).timestampMs); | ||
| await verifyCertificateChain(attestationDoc.cabundle, constants.AWS_ROOT_CERT_PEM, attestationDoc.certificate, appProofTimestampMs); | ||
| // Verify manifest digest | ||
| const decodedBootProofManifest = Uint8Array.from(atob(bootProof.qosManifestB64) | ||
| .split("") | ||
| .map((c) => c.charCodeAt(0))); | ||
| const manifestDigest = sha2.sha256(decodedBootProofManifest); | ||
| if (!bytesEq(manifestDigest, attestationDoc.user_data)) { | ||
| throw new Error(`attestationDoc's user_data doesn't match the hash of the manifest. attestationDoc.user_data: ${attestationDoc.user_data} , manifest digest: ${manifestDigest}`); | ||
| } | ||
| // 3. Verify that all the ephemeral public keys match: app proof, boot proof structure, actual attestation doc | ||
| const publicKeyBytes = new Uint8Array(attestationDoc.public_key); | ||
| const attestationPubKey = encoding.uint8ArrayToHexString(publicKeyBytes); | ||
| if (appProof.publicKey !== attestationPubKey || | ||
| attestationPubKey !== bootProof.ephemeralPublicKeyHex) { | ||
| throw new Error(`Ephemeral pub keys from app proof: ${appProof.publicKey}, boot proof structure ${bootProof.ephemeralPublicKeyHex}, and attestation doc ${attestationPubKey} should all match`); | ||
| } | ||
| } | ||
| /** | ||
| * Verify app proof signature with @noble/curves | ||
| */ | ||
| function verifyAppProofSignature(appProof) { | ||
| if (appProof.scheme !== "SIGNATURE_SCHEME_EPHEMERAL_KEY_P256") { | ||
| throw new Error("Unsupported signature scheme"); | ||
| } | ||
| // Decode public key | ||
| let publicKeyBytes; | ||
| try { | ||
| publicKeyBytes = encoding.uint8ArrayFromHexString(appProof.publicKey); | ||
| } | ||
| catch { | ||
| throw new Error("Failed to decode public key"); | ||
| } | ||
| if (publicKeyBytes.length !== 130) { | ||
| throw new Error(`Expected 130 bytes (encryption + signing pub keys), got ${publicKeyBytes.length} bytes`); | ||
| } | ||
| // Extract signing key (last 65 bytes, uncompressed P-256 point) | ||
| const signingKeyBytes = publicKeyBytes.slice(65); | ||
| if (signingKeyBytes.length !== 65 || signingKeyBytes[0] !== 0x04) { | ||
| throw new Error("Invalid signing key format: expected 65-byte uncompressed P-256 point (0x04||X||Y)"); | ||
| } | ||
| // Validate it's a valid P-256 public key by attempting to create a point | ||
| try { | ||
| p256.p256.ProjectivePoint.fromHex(signingKeyBytes); | ||
| } | ||
| catch (error) { | ||
| throw new Error(`Invalid P-256 public key: ${error}`); | ||
| } | ||
| // Decode signature (64 bytes = 32 bytes r + 32 bytes s) | ||
| let signatureBytes; | ||
| try { | ||
| signatureBytes = encoding.uint8ArrayFromHexString(appProof.signature); | ||
| } | ||
| catch { | ||
| throw new Error("Failed to decode signature"); | ||
| } | ||
| if (signatureBytes.length !== 64) { | ||
| throw new Error(`Expected 64 bytes signature (r||s), got ${signatureBytes.length} bytes`); | ||
| } | ||
| // Hash the proof payload | ||
| const payloadBytes = new TextEncoder().encode(appProof.proofPayload); | ||
| const payloadDigest = sha2.sha256(payloadBytes); | ||
| // Verify ECDSA signature | ||
| const isValid = p256.p256.verify(signatureBytes, payloadDigest, signingKeyBytes); | ||
| if (!isValid) { | ||
| throw new Error("Signature verification failed"); | ||
| } | ||
| } | ||
| async function verifyCertificateChain(cabundle, rootCertPem, leafCert, timestampMs) { | ||
| try { | ||
| // Check root and assert fingerprint | ||
| const rootX509 = new x509__namespace.X509Certificate(rootCertPem); | ||
| const rootDer = new Uint8Array(rootX509.rawData); | ||
| const rootSha = await sha256Hex(rootDer); | ||
| if (rootSha !== constants.AWS_ROOT_CERT_SHA256) { | ||
| throw new Error(`Pinned AWS root fingerprint mismatch: expected=${constants.AWS_ROOT_CERT_SHA256} actual=${rootSha}`); | ||
| } | ||
| // Bundle starts with root certificate. We're replacing the root with our hardcoded known certificate, so remove first element | ||
| const bundleWithoutRoot = cabundle.slice(1); | ||
| const intermediatesX509 = bundleWithoutRoot.map((c) => { | ||
| if (!c) | ||
| throw new Error("Invalid certificate data in cabundle"); | ||
| return new x509__namespace.X509Certificate(c); | ||
| }); | ||
| const leaf = new x509__namespace.X509Certificate(leafCert); | ||
| // Build path leaf → intermediates → root, with our hardcoded known root certificate | ||
| const builder = new x509__namespace.X509ChainBuilder({ | ||
| certificates: [rootX509, ...intermediatesX509], | ||
| }); | ||
| const chain = await builder.build(leaf); | ||
| if (chain.length !== intermediatesX509.length + 2) { | ||
| throw new Error(`Incorrect number of certs in X509 Chain. Expected ${intermediatesX509.length + 2}, got ${chain.length}`); | ||
| } | ||
| const appProofDate = new Date(timestampMs); | ||
| for (let i = 0; i < chain.length; i++) { | ||
| const cert = chain[i]; | ||
| if (!cert) | ||
| throw new Error("Invalid certificate in chain"); | ||
| if (i === chain.length - 1) { | ||
| // is root | ||
| // Self-signature verification for root certificate | ||
| const ok = await cert.verify({ | ||
| publicKey: cert.publicKey, | ||
| date: appProofDate, | ||
| }); | ||
| if (!ok) | ||
| throw new Error("Pinned root failed self-signature verification"); | ||
| } | ||
| else { | ||
| // Verify signature against issuer | ||
| const issuer = chain[i + 1]; | ||
| if (!issuer) | ||
| throw new Error("Issuer can't be null"); | ||
| // Attestation docs technically expire after 3 hours, so an app proof generated 3+ hours after an enclave | ||
| // boots up will fail verification due to certificate expiration. This is okay because enclaves are immutable; | ||
| // even if the cert is technically invalid, the code contained within it cannot change. To prevent the cert | ||
| // expiration failure, we set `signatureOnly: true`. | ||
| const ok = await cert.verify({ | ||
| publicKey: issuer.publicKey, | ||
| signatureOnly: true, | ||
| date: appProofDate, | ||
| }); | ||
| if (!ok) { | ||
| throw new Error(`Signature check failed: ${cert.subject} not signed by ${issuer?.subject}`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch (error) { | ||
| throw new Error(`Certificate chain verification failed: ${error instanceof Error ? error.message : String(error)}`); | ||
| } | ||
| } | ||
| async function verifyCoseSign1Sig(coseSign1, leaf) { | ||
| const [protectedHeaders, , payload, signature] = coseSign1; | ||
| const tbs = new Uint8Array(CBOR__namespace.encode([ | ||
| "Signature1", | ||
| new Uint8Array(protectedHeaders), | ||
| new Uint8Array(0), | ||
| new Uint8Array(payload), | ||
| ])); | ||
| const leafCert = new x509__namespace.X509Certificate(leaf); | ||
| const pubKey = await importEcdsaPublicKey(leafCert.publicKey.rawData); | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| const ok = await cryptoInstance.subtle.verify({ name: "ECDSA", hash: { name: "SHA-384" } }, pubKey, new Uint8Array(signature), tbs); | ||
| if (!ok) | ||
| throw new Error("COSE_Sign1 ES384 verification failed"); | ||
| } | ||
| function bytesEq(a, b) { | ||
| const A = new Uint8Array(a), B = new Uint8Array(b); | ||
| if (A.length !== B.length) | ||
| return false; | ||
| for (let i = 0; i < A.length; i++) | ||
| if (A[i] !== B[i]) | ||
| return false; | ||
| return true; | ||
| } | ||
| exports.getCryptoInstance = getCryptoInstance; | ||
| exports.verify = verify; | ||
| exports.verifyAppProofSignature = verifyAppProofSignature; | ||
| exports.verifyCertificateChain = verifyCertificateChain; | ||
| exports.verifyCoseSign1Sig = verifyCoseSign1Sig; | ||
| //# sourceMappingURL=proof.js.map |
| {"version":3,"file":"proof.js","sources":["../src/proof.ts"],"sourcesContent":[null],"names":["x509","uint8ArrayToHexString","CBOR","AWS_ROOT_CERT_PEM","sha256","uint8ArrayFromHexString","p256","AWS_ROOT_CERT_SHA256"],"mappings":"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"} |
+228
| import { uint8ArrayToHexString, uint8ArrayFromHexString } from '@turnkey/encoding'; | ||
| import { p256 } from '@noble/curves/p256'; | ||
| import { sha256 } from '@noble/hashes/sha2'; | ||
| import * as CBOR from 'cbor-js'; | ||
| import * as x509 from '@peculiar/x509'; | ||
| import { AWS_ROOT_CERT_PEM, AWS_ROOT_CERT_SHA256 } from './constants.mjs'; | ||
| const getCryptoInstance = async () => { | ||
| let cryptoInstance; | ||
| // Use globalThis.crypto.subtle if available | ||
| if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) { | ||
| cryptoInstance = globalThis.crypto; | ||
| x509.cryptoProvider.set(cryptoInstance); | ||
| return cryptoInstance; | ||
| } | ||
| try { | ||
| // Dynamic import to prevent bundling in environments that already have WebCrypto | ||
| const { Crypto: PeculiarCrypto } = await import('@peculiar/webcrypto'); | ||
| cryptoInstance = new PeculiarCrypto(); | ||
| x509.cryptoProvider.set(cryptoInstance); | ||
| return cryptoInstance; | ||
| } | ||
| catch { | ||
| // Happens usually on React Native | ||
| throw new Error("No WebCrypto implementation found. " + | ||
| "In React Native, please polyfill `global.crypto.subtle` (e.g., with `react-native-webcrypto`) " + | ||
| "before calling verify()."); | ||
| } | ||
| }; | ||
| /** | ||
| * Utility: SHA-256 digest → hex (uppercase) | ||
| */ | ||
| async function sha256Hex(data) { | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| const digest = await cryptoInstance.subtle.digest("SHA-256", data); | ||
| return uint8ArrayToHexString(new Uint8Array(digest)).toUpperCase(); | ||
| } | ||
| /** | ||
| * Utility: Import SPKI public key for ECDSA verify | ||
| */ | ||
| async function importEcdsaPublicKey(spki) { | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| return cryptoInstance.subtle.importKey("spki", spki, { name: "ECDSA", namedCurve: "P-384" }, // AWS Nitro uses ES384 | ||
| false, ["verify"]); | ||
| } | ||
| /** | ||
| * verify goes through the following verification steps for an app proof & boot proof pair: | ||
| * - Verify app proof signature | ||
| * - Verify the boot proof | ||
| * - Attestation doc was signed by AWS | ||
| * - Attestation doc's `user_data` is the hash of the qos manifest | ||
| * - Verify the connection between the app proof & boot proof i.e. that the ephemeral keys match | ||
| * | ||
| * For more information, check out https://whitepaper.turnkey.com/foundations | ||
| */ | ||
| async function verify(appProof, bootProof) { | ||
| // 1. Verify App Proof | ||
| verifyAppProofSignature(appProof); | ||
| // 2. Verify Boot Proof | ||
| // Parse attestation | ||
| const coseSign1Der = Uint8Array.from(atob(bootProof.awsAttestationDocB64) | ||
| .split("") | ||
| .map((c) => c.charCodeAt(0))); | ||
| const coseSign1 = CBOR.decode(coseSign1Der.buffer); | ||
| const [, , payload] = coseSign1; | ||
| const attestationDoc = CBOR.decode(new Uint8Array(payload).buffer); | ||
| // Verify cose sign1 signature | ||
| await verifyCoseSign1Sig(coseSign1, attestationDoc.certificate); | ||
| // Verify certificate chain | ||
| const appProofTimestampMs = parseInt(JSON.parse(appProof.proofPayload).timestampMs); | ||
| await verifyCertificateChain(attestationDoc.cabundle, AWS_ROOT_CERT_PEM, attestationDoc.certificate, appProofTimestampMs); | ||
| // Verify manifest digest | ||
| const decodedBootProofManifest = Uint8Array.from(atob(bootProof.qosManifestB64) | ||
| .split("") | ||
| .map((c) => c.charCodeAt(0))); | ||
| const manifestDigest = sha256(decodedBootProofManifest); | ||
| if (!bytesEq(manifestDigest, attestationDoc.user_data)) { | ||
| throw new Error(`attestationDoc's user_data doesn't match the hash of the manifest. attestationDoc.user_data: ${attestationDoc.user_data} , manifest digest: ${manifestDigest}`); | ||
| } | ||
| // 3. Verify that all the ephemeral public keys match: app proof, boot proof structure, actual attestation doc | ||
| const publicKeyBytes = new Uint8Array(attestationDoc.public_key); | ||
| const attestationPubKey = uint8ArrayToHexString(publicKeyBytes); | ||
| if (appProof.publicKey !== attestationPubKey || | ||
| attestationPubKey !== bootProof.ephemeralPublicKeyHex) { | ||
| throw new Error(`Ephemeral pub keys from app proof: ${appProof.publicKey}, boot proof structure ${bootProof.ephemeralPublicKeyHex}, and attestation doc ${attestationPubKey} should all match`); | ||
| } | ||
| } | ||
| /** | ||
| * Verify app proof signature with @noble/curves | ||
| */ | ||
| function verifyAppProofSignature(appProof) { | ||
| if (appProof.scheme !== "SIGNATURE_SCHEME_EPHEMERAL_KEY_P256") { | ||
| throw new Error("Unsupported signature scheme"); | ||
| } | ||
| // Decode public key | ||
| let publicKeyBytes; | ||
| try { | ||
| publicKeyBytes = uint8ArrayFromHexString(appProof.publicKey); | ||
| } | ||
| catch { | ||
| throw new Error("Failed to decode public key"); | ||
| } | ||
| if (publicKeyBytes.length !== 130) { | ||
| throw new Error(`Expected 130 bytes (encryption + signing pub keys), got ${publicKeyBytes.length} bytes`); | ||
| } | ||
| // Extract signing key (last 65 bytes, uncompressed P-256 point) | ||
| const signingKeyBytes = publicKeyBytes.slice(65); | ||
| if (signingKeyBytes.length !== 65 || signingKeyBytes[0] !== 0x04) { | ||
| throw new Error("Invalid signing key format: expected 65-byte uncompressed P-256 point (0x04||X||Y)"); | ||
| } | ||
| // Validate it's a valid P-256 public key by attempting to create a point | ||
| try { | ||
| p256.ProjectivePoint.fromHex(signingKeyBytes); | ||
| } | ||
| catch (error) { | ||
| throw new Error(`Invalid P-256 public key: ${error}`); | ||
| } | ||
| // Decode signature (64 bytes = 32 bytes r + 32 bytes s) | ||
| let signatureBytes; | ||
| try { | ||
| signatureBytes = uint8ArrayFromHexString(appProof.signature); | ||
| } | ||
| catch { | ||
| throw new Error("Failed to decode signature"); | ||
| } | ||
| if (signatureBytes.length !== 64) { | ||
| throw new Error(`Expected 64 bytes signature (r||s), got ${signatureBytes.length} bytes`); | ||
| } | ||
| // Hash the proof payload | ||
| const payloadBytes = new TextEncoder().encode(appProof.proofPayload); | ||
| const payloadDigest = sha256(payloadBytes); | ||
| // Verify ECDSA signature | ||
| const isValid = p256.verify(signatureBytes, payloadDigest, signingKeyBytes); | ||
| if (!isValid) { | ||
| throw new Error("Signature verification failed"); | ||
| } | ||
| } | ||
| async function verifyCertificateChain(cabundle, rootCertPem, leafCert, timestampMs) { | ||
| try { | ||
| // Check root and assert fingerprint | ||
| const rootX509 = new x509.X509Certificate(rootCertPem); | ||
| const rootDer = new Uint8Array(rootX509.rawData); | ||
| const rootSha = await sha256Hex(rootDer); | ||
| if (rootSha !== AWS_ROOT_CERT_SHA256) { | ||
| throw new Error(`Pinned AWS root fingerprint mismatch: expected=${AWS_ROOT_CERT_SHA256} actual=${rootSha}`); | ||
| } | ||
| // Bundle starts with root certificate. We're replacing the root with our hardcoded known certificate, so remove first element | ||
| const bundleWithoutRoot = cabundle.slice(1); | ||
| const intermediatesX509 = bundleWithoutRoot.map((c) => { | ||
| if (!c) | ||
| throw new Error("Invalid certificate data in cabundle"); | ||
| return new x509.X509Certificate(c); | ||
| }); | ||
| const leaf = new x509.X509Certificate(leafCert); | ||
| // Build path leaf → intermediates → root, with our hardcoded known root certificate | ||
| const builder = new x509.X509ChainBuilder({ | ||
| certificates: [rootX509, ...intermediatesX509], | ||
| }); | ||
| const chain = await builder.build(leaf); | ||
| if (chain.length !== intermediatesX509.length + 2) { | ||
| throw new Error(`Incorrect number of certs in X509 Chain. Expected ${intermediatesX509.length + 2}, got ${chain.length}`); | ||
| } | ||
| const appProofDate = new Date(timestampMs); | ||
| for (let i = 0; i < chain.length; i++) { | ||
| const cert = chain[i]; | ||
| if (!cert) | ||
| throw new Error("Invalid certificate in chain"); | ||
| if (i === chain.length - 1) { | ||
| // is root | ||
| // Self-signature verification for root certificate | ||
| const ok = await cert.verify({ | ||
| publicKey: cert.publicKey, | ||
| date: appProofDate, | ||
| }); | ||
| if (!ok) | ||
| throw new Error("Pinned root failed self-signature verification"); | ||
| } | ||
| else { | ||
| // Verify signature against issuer | ||
| const issuer = chain[i + 1]; | ||
| if (!issuer) | ||
| throw new Error("Issuer can't be null"); | ||
| // Attestation docs technically expire after 3 hours, so an app proof generated 3+ hours after an enclave | ||
| // boots up will fail verification due to certificate expiration. This is okay because enclaves are immutable; | ||
| // even if the cert is technically invalid, the code contained within it cannot change. To prevent the cert | ||
| // expiration failure, we set `signatureOnly: true`. | ||
| const ok = await cert.verify({ | ||
| publicKey: issuer.publicKey, | ||
| signatureOnly: true, | ||
| date: appProofDate, | ||
| }); | ||
| if (!ok) { | ||
| throw new Error(`Signature check failed: ${cert.subject} not signed by ${issuer?.subject}`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch (error) { | ||
| throw new Error(`Certificate chain verification failed: ${error instanceof Error ? error.message : String(error)}`); | ||
| } | ||
| } | ||
| async function verifyCoseSign1Sig(coseSign1, leaf) { | ||
| const [protectedHeaders, , payload, signature] = coseSign1; | ||
| const tbs = new Uint8Array(CBOR.encode([ | ||
| "Signature1", | ||
| new Uint8Array(protectedHeaders), | ||
| new Uint8Array(0), | ||
| new Uint8Array(payload), | ||
| ])); | ||
| const leafCert = new x509.X509Certificate(leaf); | ||
| const pubKey = await importEcdsaPublicKey(leafCert.publicKey.rawData); | ||
| const cryptoInstance = await getCryptoInstance(); | ||
| const ok = await cryptoInstance.subtle.verify({ name: "ECDSA", hash: { name: "SHA-384" } }, pubKey, new Uint8Array(signature), tbs); | ||
| if (!ok) | ||
| throw new Error("COSE_Sign1 ES384 verification failed"); | ||
| } | ||
| function bytesEq(a, b) { | ||
| const A = new Uint8Array(a), B = new Uint8Array(b); | ||
| if (A.length !== B.length) | ||
| return false; | ||
| for (let i = 0; i < A.length; i++) | ||
| if (A[i] !== B[i]) | ||
| return false; | ||
| return true; | ||
| } | ||
| export { getCryptoInstance, verify, verifyAppProofSignature, verifyCertificateChain, verifyCoseSign1Sig }; | ||
| //# sourceMappingURL=proof.mjs.map |
| {"version":3,"file":"proof.mjs","sources":["../src/proof.ts"],"sourcesContent":[null],"names":[],"mappings":"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"} |
+9
-0
| # @turnkey/crypto | ||
| ## 2.8.3 | ||
| ### Patch Changes | ||
| - [#992](https://github.com/tkhq/sdk/pull/992) [`5c4495b`](https://github.com/tkhq/sdk/commit/5c4495bff1b0abfe3c427ead1b8e1a8d510c8186) Author [@amircheikh](https://github.com/amircheikh) - - `verify` function is now exposed and supports web platforms | ||
| - Updated dependencies [[`5c4495b`](https://github.com/tkhq/sdk/commit/5c4495bff1b0abfe3c427ead1b8e1a8d510c8186)]: | ||
| - @turnkey/sdk-types@0.6.3 | ||
| ## 2.8.2 | ||
@@ -4,0 +13,0 @@ |
+19
-0
@@ -33,4 +33,23 @@ 'use strict'; | ||
| const PRODUCTION_ON_RAMP_CREDENTIALS_ENCRYPTION_PUBLIC_KEY = "02336ebd7e929ef64b87c776b72540255b4c7b41579a24b1e68fb060daa873f9f6"; | ||
| // Pinned AWS Nitro Enclaves Root | ||
| const AWS_ROOT_CERT_PEM = `-----BEGIN CERTIFICATE----- | ||
| MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL | ||
| MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD | ||
| VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4 | ||
| MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL | ||
| DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG | ||
| BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb | ||
| 48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE | ||
| h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF | ||
| R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC | ||
| MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW | ||
| rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N | ||
| IwLz3/Y= | ||
| -----END CERTIFICATE-----`; | ||
| // Official SHA-256 fingerprint | ||
| const AWS_ROOT_CERT_SHA256 = "641A0321A3E244EFE456463195D606317ED7CDCC3C1756E09893F3C68F79BB5B"; | ||
| exports.AES_KEY_INFO = AES_KEY_INFO; | ||
| exports.AWS_ROOT_CERT_PEM = AWS_ROOT_CERT_PEM; | ||
| exports.AWS_ROOT_CERT_SHA256 = AWS_ROOT_CERT_SHA256; | ||
| exports.HPKE_VERSION = HPKE_VERSION; | ||
@@ -37,0 +56,0 @@ exports.IV_INFO = IV_INFO; |
+18
-1
@@ -31,4 +31,21 @@ const SUITE_ID_1 = new Uint8Array([75, 69, 77, 0, 16]); //KEM suite ID | ||
| const PRODUCTION_ON_RAMP_CREDENTIALS_ENCRYPTION_PUBLIC_KEY = "02336ebd7e929ef64b87c776b72540255b4c7b41579a24b1e68fb060daa873f9f6"; | ||
| // Pinned AWS Nitro Enclaves Root | ||
| const AWS_ROOT_CERT_PEM = `-----BEGIN CERTIFICATE----- | ||
| MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL | ||
| MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD | ||
| VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4 | ||
| MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL | ||
| DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG | ||
| BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb | ||
| 48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE | ||
| h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF | ||
| R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC | ||
| MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW | ||
| rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N | ||
| IwLz3/Y= | ||
| -----END CERTIFICATE-----`; | ||
| // Official SHA-256 fingerprint | ||
| const AWS_ROOT_CERT_SHA256 = "641A0321A3E244EFE456463195D606317ED7CDCC3C1756E09893F3C68F79BB5B"; | ||
| export { AES_KEY_INFO, HPKE_VERSION, IV_INFO, LABEL_EAE_PRK, LABEL_SECRET, LABEL_SHARED_SECRET, PRODUCTION_NOTARIZER_SIGN_PUBLIC_KEY, PRODUCTION_ON_RAMP_CREDENTIALS_ENCRYPTION_PUBLIC_KEY, PRODUCTION_SIGNER_SIGN_PUBLIC_KEY, PRODUCTION_TLS_FETCHER_ENCRYPT_PUBLIC_KEY, QOS_ENCRYPTION_HMAC_MESSAGE, QUORUM_ENCRYPT_NONCE_LENGTH_BYTES, SUITE_ID_1, SUITE_ID_2, UNCOMPRESSED_PUB_KEY_LENGTH_BYTES }; | ||
| export { AES_KEY_INFO, AWS_ROOT_CERT_PEM, AWS_ROOT_CERT_SHA256, HPKE_VERSION, IV_INFO, LABEL_EAE_PRK, LABEL_SECRET, LABEL_SHARED_SECRET, PRODUCTION_NOTARIZER_SIGN_PUBLIC_KEY, PRODUCTION_ON_RAMP_CREDENTIALS_ENCRYPTION_PUBLIC_KEY, PRODUCTION_SIGNER_SIGN_PUBLIC_KEY, PRODUCTION_TLS_FETCHER_ENCRYPT_PUBLIC_KEY, QOS_ENCRYPTION_HMAC_MESSAGE, QUORUM_ENCRYPT_NONCE_LENGTH_BYTES, SUITE_ID_1, SUITE_ID_2, UNCOMPRESSED_PUB_KEY_LENGTH_BYTES }; | ||
| //# sourceMappingURL=constants.mjs.map |
+1
-0
| export * from "./crypto"; | ||
| export * from "./turnkey"; | ||
| export * from "./proof"; | ||
| //# sourceMappingURL=index.d.ts.map |
+6
-0
@@ -5,2 +5,3 @@ 'use strict'; | ||
| var turnkey = require('./turnkey.js'); | ||
| var proof = require('./proof.js'); | ||
@@ -35,2 +36,7 @@ | ||
| exports.verifyStampSignature = turnkey.verifyStampSignature; | ||
| exports.getCryptoInstance = proof.getCryptoInstance; | ||
| exports.verify = proof.verify; | ||
| exports.verifyAppProofSignature = proof.verifyAppProofSignature; | ||
| exports.verifyCertificateChain = proof.verifyCertificateChain; | ||
| exports.verifyCoseSign1Sig = proof.verifyCoseSign1Sig; | ||
| //# sourceMappingURL=index.js.map |
+1
-0
| export { buildAdditionalAssociatedData, compressRawPublicKey, extractPrivateKeyFromPKCS8Bytes, formatHpkeBuf, fromDerSignature, generateP256KeyPair, getPublicKey, hpkeAuthEncrypt, hpkeDecrypt, hpkeEncrypt, quorumKeyEncrypt, toDerSignature, uncompressRawPublicKey } from './crypto.mjs'; | ||
| export { Enclave, decryptCredentialBundle, decryptExportBundle, encryptOauth2ClientSecret, encryptOnRampSecret, encryptPrivateKeyToBundle, encryptToEnclave, encryptWalletToBundle, verifySessionJwtSignature, verifyStampSignature } from './turnkey.mjs'; | ||
| export { getCryptoInstance, verify, verifyAppProofSignature, verifyCertificateChain, verifyCoseSign1Sig } from './proof.mjs'; | ||
| //# sourceMappingURL=index.mjs.map |
+6
-2
| import type { v1AppProof, v1BootProof } from "@turnkey/sdk-types"; | ||
| export declare const getCryptoInstance: () => Promise<Crypto>; | ||
| /** | ||
@@ -10,8 +11,11 @@ * verify goes through the following verification steps for an app proof & boot proof pair: | ||
| * | ||
| * For more information, check out https://whitepaper.turnkey.com/foundations | ||
| * For more information, check out https://whitepaper.turnkey.com/foundations | ||
| */ | ||
| export declare function verify(appProof: v1AppProof, bootProof: v1BootProof): Promise<void>; | ||
| /** | ||
| * Verify app proof signature with @noble/curves | ||
| */ | ||
| export declare function verifyAppProofSignature(appProof: v1AppProof): void; | ||
| export declare function verifyCertificateChain(cabundle: Uint8Array[], rootCertPem: string, leafCert: Uint8Array, timestampMs: number): Promise<void>; | ||
| export declare function verifyCoseSign1Sig(coseSign1: any, leaf: Uint8Array): void; | ||
| export declare function verifyCoseSign1Sig(coseSign1: any, leaf: Uint8Array): Promise<void>; | ||
| //# sourceMappingURL=proof.d.ts.map |
+2
-2
| { | ||
| "name": "@turnkey/crypto", | ||
| "version": "2.8.2", | ||
| "version": "2.8.3", | ||
| "main": "./dist/index.js", | ||
@@ -46,3 +46,3 @@ "module": "./dist/index.mjs", | ||
| "@turnkey/encoding": "0.6.0", | ||
| "@turnkey/sdk-types": "0.6.2" | ||
| "@turnkey/sdk-types": "0.6.3" | ||
| }, | ||
@@ -49,0 +49,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
253106
18.41%40
11.11%2991
21.19%7
Infinity%+ Added
- Removed
Updated