blob: 8ddda97741d022cd77e143260dbfef0175b02d00 [file] [log] [blame]
// Copyright (c) 2012 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 "net/spdy/spdy_credential_builder.h"
#include "base/logging.h"
#include "base/string_piece.h"
#include "crypto/ec_private_key.h"
#include "crypto/ec_signature_creator.h"
#include "net/base/asn1_util.h"
#include "net/base/server_bound_cert_service.h"
#include "net/base/net_errors.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_framer.h"
namespace net {
namespace {
std::vector<uint8> ToVector(base::StringPiece piece) {
return std::vector<uint8>(piece.data(), piece.data() + piece.length());
}
} // namespace
// static
int SpdyCredentialBuilder::Build(const std::string& tls_unique,
SSLClientCertType type,
const std::string& key,
const std::string& cert,
size_t slot,
SpdyCredential* credential) {
if (type != CLIENT_CERT_ECDSA_SIGN)
return ERR_BAD_SSL_CLIENT_AUTH_CERT;
std::string secret = SpdyCredentialBuilder::GetCredentialSecret(tls_unique);
// Extract the SubjectPublicKeyInfo from the certificate.
base::StringPiece public_key_info;
if(!asn1::ExtractSPKIFromDERCert(cert, &public_key_info))
return ERR_BAD_SSL_CLIENT_AUTH_CERT;
// Next, extract the SubjectPublicKey data, which will actually
// be stored in the cert field of the credential frame.
base::StringPiece public_key;
if (!asn1::ExtractSubjectPublicKeyFromSPKI(public_key_info, &public_key))
return ERR_BAD_SSL_CLIENT_AUTH_CERT;
// Drop one byte of padding bits count from the BIT STRING
// (this will always be zero). Drop one byte of X9.62 format specification
// (this will always be 4 to indicated an uncompressed point).
DCHECK_GT(public_key.length(), 2u);
DCHECK_EQ(0, static_cast<int>(public_key[0]));
DCHECK_EQ(4, static_cast<int>(public_key[1]));
public_key = public_key.substr(2, public_key.length());
// Convert the strings into a vector<unit8>
std::vector<uint8> der_signature;
scoped_ptr<crypto::ECPrivateKey> private_key(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
ServerBoundCertService::kEPKIPassword,
ToVector(key), ToVector(public_key_info)));
scoped_ptr<crypto::ECSignatureCreator> creator(
crypto::ECSignatureCreator::Create(private_key.get()));
creator->Sign(reinterpret_cast<const unsigned char *>(secret.data()),
secret.length(), &der_signature);
std::vector<uint8> proof_vector;
if (!creator->DecodeSignature(der_signature, &proof_vector)) {
NOTREACHED();
return ERR_UNEXPECTED;
}
credential->slot = slot;
credential->certs.push_back(public_key.as_string());
credential->proof.assign(proof_vector.begin(), proof_vector.end());
return OK;
}
// static
std::string SpdyCredentialBuilder::GetCredentialSecret(
const std::string& tls_unique) {
const char prefix[] = "SPDY CREDENTIAL ChannelID\0client -> server";
std::string secret(prefix, arraysize(prefix));
secret.append(tls_unique);
return secret;
}
} // namespace net