gecko-dev/dom/webauthn/WebAuthnCBORUtil.cpp
Tim Taubert 4c6fab9bac Bug 1416056 - Web Authentication - Default to "None Attestation" r=jcj
Summary:
Always replace attestation statements with a "none" attestation.

Bug 1430150 will introduce a prompt that asks the user for permission whenever
the RP requests "direct" attestation. Only if the user opts in we will forward
the attestation statement with the token's certificate and signature.

Reviewers: jcj

Reviewed By: jcj

Bug #: 1416056

Differential Revision: https://phabricator.services.mozilla.com/D567
2018-02-09 16:34:39 +01:00

136 lines
3.8 KiB
C++

/* -*- 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;
}
}
}