1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/spdy/spdy_credential_builder.h"
6
7#include "base/logging.h"
8#include "base/strings/string_piece.h"
9#include "crypto/ec_private_key.h"
10#include "crypto/ec_signature_creator.h"
11#include "net/base/net_errors.h"
12#include "net/cert/asn1_util.h"
13#include "net/socket/ssl_client_socket.h"
14#include "net/spdy/spdy_framer.h"
15#include "net/ssl/server_bound_cert_service.h"
16
17namespace net {
18
19namespace {
20
21std::vector<uint8> ToVector(base::StringPiece piece) {
22  return std::vector<uint8>(piece.data(), piece.data() + piece.length());
23}
24
25}  // namespace
26
27// static
28int SpdyCredentialBuilder::Build(const std::string& tls_unique,
29                                 const std::string& key,
30                                 const std::string& cert,
31                                 size_t slot,
32                                 SpdyCredential* credential) {
33  std::string secret = SpdyCredentialBuilder::GetCredentialSecret(tls_unique);
34
35  // Extract the SubjectPublicKeyInfo from the certificate.
36  base::StringPiece public_key_info;
37  if(!asn1::ExtractSPKIFromDERCert(cert, &public_key_info))
38    return ERR_BAD_SSL_CLIENT_AUTH_CERT;
39
40  // Next, extract the SubjectPublicKey data, which will actually
41  // be stored in the cert field of the credential frame.
42  base::StringPiece public_key;
43  if (!asn1::ExtractSubjectPublicKeyFromSPKI(public_key_info, &public_key))
44    return ERR_BAD_SSL_CLIENT_AUTH_CERT;
45  // Drop one byte of padding bits count from the BIT STRING
46  // (this will always be zero).  Drop one byte of X9.62 format specification
47  // (this will always be 4 to indicated an uncompressed point).
48  DCHECK_GT(public_key.length(), 2u);
49  DCHECK_EQ(0, static_cast<int>(public_key[0]));
50  DCHECK_EQ(4, static_cast<int>(public_key[1]));
51  public_key = public_key.substr(2, public_key.length());
52
53  // Convert the strings into a vector<unit8>
54  std::vector<uint8> der_signature;
55  scoped_ptr<crypto::ECPrivateKey> private_key(
56      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
57          ServerBoundCertService::kEPKIPassword,
58          ToVector(key), ToVector(public_key_info)));
59  scoped_ptr<crypto::ECSignatureCreator> creator(
60      crypto::ECSignatureCreator::Create(private_key.get()));
61  creator->Sign(reinterpret_cast<const unsigned char *>(secret.data()),
62                secret.length(), &der_signature);
63
64  std::vector<uint8> proof_vector;
65  if (!creator->DecodeSignature(der_signature, &proof_vector)) {
66    NOTREACHED();
67    return ERR_UNEXPECTED;
68  }
69
70  credential->slot = slot;
71  credential->certs.push_back(public_key.as_string());
72  credential->proof.assign(proof_vector.begin(), proof_vector.end());
73  return OK;
74}
75
76// static
77std::string SpdyCredentialBuilder::GetCredentialSecret(
78    const std::string& tls_unique) {
79  const char prefix[] = "SPDY CREDENTIAL ChannelID\0client -> server";
80  std::string secret(prefix, arraysize(prefix));
81  secret.append(tls_unique);
82
83  return secret;
84}
85
86}  // namespace net
87