blob: f4f00d442b659511800a7e784324c83d3c0368fc [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/webauth/fido_attestation_statement.h"
#include <utility>
#include "base/numerics/safe_conversions.h"
#include "content/browser/webauth/authenticator_utils.h"
#include "content/browser/webauth/cbor/cbor_writer.h"
namespace content {
namespace {
constexpr char kFidoFormatName[] = "fido-u2f";
constexpr char kSignatureKey[] = "sig";
constexpr char kX509CertKey[] = "x5c";
} // namespace
// static
std::unique_ptr<FidoAttestationStatement>
FidoAttestationStatement::CreateFromU2fRegisterResponse(
const std::vector<uint8_t>& u2f_data) {
std::vector<std::vector<uint8_t>> x509_certificates;
std::vector<uint8_t> x509_cert;
// Extract the length length of the credential (i.e. of U2FResponse key
// handle). Length is big endian and is located at position 66 in the data.
// Note that U2F responses only use one byte for length.
std::vector<uint8_t> id_length(2, 0);
CHECK_GE(u2f_data.size(), authenticator_utils::kU2fResponseLengthPos + 1);
id_length[1] = u2f_data[authenticator_utils::kU2fResponseLengthPos];
size_t id_end_byte = authenticator_utils::kU2fResponseKeyHandleStartPos +
((base::strict_cast<uint32_t>(id_length[0]) << 8) |
(base::strict_cast<uint32_t>(id_length[1])));
// Parse x509 cert to get cert length (which is variable).
// TODO: Support responses with multiple certs.
int num_bytes = 0;
uint32_t cert_length = 0;
// The first x509 byte is a tag, so we skip it.
size_t first_length_byte =
base::strict_cast<size_t>(u2f_data[id_end_byte + 1]);
// If the first length byte is less than 127, it is the length. If it is
// greater than 128, it indicates the number of following bytes that encode
// the length.
if (first_length_byte > 127) {
num_bytes = first_length_byte - 128;
// x509 cert length, interpreted big-endian.
for (int i = 1; i <= num_bytes; i++) {
// Account for tag byte and length details byte.
cert_length |= base::checked_cast<uint32_t>(u2f_data[id_end_byte + 1 + i]
<< ((num_bytes - i) * 8));
}
} else {
cert_length = first_length_byte;
}
size_t x509_length = 1 /* tag byte */ + 1 /* first length byte */
+ num_bytes /* # bytes of length */ + cert_length;
authenticator_utils::Append(
&x509_cert,
authenticator_utils::Extract(u2f_data, id_end_byte, x509_length));
x509_certificates.push_back(x509_cert);
// The remaining bytes are the signature.
std::vector<uint8_t> signature;
size_t signature_start_byte = id_end_byte + x509_length;
authenticator_utils::Append(
&signature,
authenticator_utils::Extract(u2f_data, signature_start_byte,
u2f_data.size() - signature_start_byte));
return std::make_unique<FidoAttestationStatement>(signature,
x509_certificates);
}
FidoAttestationStatement::FidoAttestationStatement(
std::vector<uint8_t> signature,
std::vector<std::vector<uint8_t>> x509_certificates)
: AttestationStatement(kFidoFormatName),
signature_(std::move(signature)),
x509_certificates_(std::move(x509_certificates)) {}
CBORValue::MapValue FidoAttestationStatement::GetAsCBORMap() {
CBORValue::MapValue attstmt_map;
attstmt_map[kSignatureKey] = CBORValue(signature_);
std::vector<CBORValue> array;
for (auto cert : x509_certificates_) {
array.push_back(CBORValue(cert));
}
attstmt_map[kX509CertKey] = CBORValue(array);
return attstmt_map;
}
FidoAttestationStatement::~FidoAttestationStatement() {}
} // namespace content