summaryrefslogtreecommitdiffstats
path: root/dom/webauthn/WebAuthnCBORUtil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webauthn/WebAuthnCBORUtil.cpp')
-rw-r--r--dom/webauthn/WebAuthnCBORUtil.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/dom/webauthn/WebAuthnCBORUtil.cpp b/dom/webauthn/WebAuthnCBORUtil.cpp
new file mode 100644
index 0000000000..51255e80d8
--- /dev/null
+++ b/dom/webauthn/WebAuthnCBORUtil.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cbor-cpp/src/cbor.h"
+#include "mozilla/dom/WebAuthnCBORUtil.h"
+#include "mozilla/dom/WebAuthnUtil.h"
+
+namespace mozilla::dom {
+
+nsresult CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
+ /* out */ CryptoBuffer& aPubKeyObj) {
+ mozilla::dom::CryptoBuffer xBuf, yBuf;
+ nsresult rv = U2FDecomposeECKey(aPubKeyBuf, xBuf, yBuf);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // COSE_Key object. See https://tools.ietf.org/html/rfc8152#section-7
+ cbor::output_dynamic cborPubKeyOut;
+ cbor::encoder encoder(cborPubKeyOut);
+ encoder.write_map(5);
+ {
+ encoder.write_int(1); // kty
+ encoder.write_int(2); // EC2
+ encoder.write_int(3); // alg
+ encoder.write_int(-7); // ES256
+
+ // See https://tools.ietf.org/html/rfc8152#section-13.1
+ encoder.write_int(-1); // crv
+ encoder.write_int(1); // P-256
+ encoder.write_int(-2); // x
+ encoder.write_bytes(xBuf.Elements(), xBuf.Length());
+ encoder.write_int(-3); // y
+ encoder.write_bytes(yBuf.Elements(), yBuf.Length());
+ }
+
+ if (!aPubKeyObj.Assign(cborPubKeyOut.data(), cborPubKeyOut.size())) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ return NS_OK;
+}
+
+nsresult CBOREncodeFidoU2FAttestationObj(
+ const CryptoBuffer& aAuthDataBuf, const CryptoBuffer& aAttestationCertBuf,
+ const CryptoBuffer& aSignatureBuf,
+ /* out */ CryptoBuffer& aAttestationObj) {
+ /*
+ Attestation Object, encoded in CBOR (description is CDDL)
+
+ attObj = {
+ authData: bytes,
+ $$attStmtType
+ }
+ $$attStmtType //= (
+ fmt: "fido-u2f",
+ attStmt: u2fStmtFormat
+ )
+ u2fStmtFormat = {
+ x5c: [ attestnCert: bytes, * (caCert: bytes) ],
+ sig: bytes
+ }
+ */
+ cbor::output_dynamic cborAttOut;
+ cbor::encoder encoder(cborAttOut);
+ encoder.write_map(3);
+ {
+ encoder.write_string("fmt");
+ encoder.write_string("fido-u2f");
+
+ encoder.write_string("attStmt");
+ encoder.write_map(2);
+ {
+ encoder.write_string("sig");
+ encoder.write_bytes(aSignatureBuf.Elements(), aSignatureBuf.Length());
+
+ encoder.write_string("x5c");
+ // U2F wire protocol can only deliver 1 certificate, so it's never a chain
+ encoder.write_array(1);
+ encoder.write_bytes(aAttestationCertBuf.Elements(),
+ aAttestationCertBuf.Length());
+ }
+
+ encoder.write_string("authData");
+ encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
+ }
+
+ if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ return NS_OK;
+}
+
+nsresult CBOREncodeNoneAttestationObj(const CryptoBuffer& aAuthDataBuf,
+ /* out */ CryptoBuffer& aAttestationObj) {
+ /*
+ Attestation Object, encoded in CBOR (description is CDDL)
+
+ $$attStmtType //= (
+ fmt: "none",
+ attStmt: emptyMap
+ )
+
+ emptyMap = {}
+ */
+ cbor::output_dynamic cborAttOut;
+ cbor::encoder encoder(cborAttOut);
+ encoder.write_map(3);
+ {
+ encoder.write_string("fmt");
+ encoder.write_string("none");
+
+ encoder.write_string("attStmt");
+ encoder.write_map(0);
+
+ encoder.write_string("authData");
+ encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
+ }
+
+ if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ return NS_OK;
+}
+
+} // namespace mozilla::dom