// 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
