diff options
Diffstat (limited to '')
-rw-r--r-- | dom/webauthn/WebAuthnCBORUtil.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/dom/webauthn/WebAuthnCBORUtil.cpp b/dom/webauthn/WebAuthnCBORUtil.cpp new file mode 100644 index 0000000000..da3b05a45c --- /dev/null +++ b/dom/webauthn/WebAuthnCBORUtil.cpp @@ -0,0 +1,130 @@ +/* -*- 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 { +namespace 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 dom +} // namespace mozilla |