1// Copyright 2013 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/quic/crypto/channel_id.h"
6
7#include <keythi.h>
8#include <pk11pub.h>
9#include <sechash.h>
10
11using base::StringPiece;
12
13namespace net {
14
15// static
16bool ChannelIDVerifier::Verify(StringPiece key,
17                               StringPiece signed_data,
18                               StringPiece signature) {
19  return VerifyRaw(key, signed_data, signature, true);
20}
21
22// static
23bool ChannelIDVerifier::VerifyRaw(StringPiece key,
24                                  StringPiece signed_data,
25                                  StringPiece signature,
26                                  bool is_channel_id_signature) {
27  if (key.size() != 32 * 2 ||
28      signature.size() != 32 * 2) {
29    return false;
30  }
31
32  SECKEYPublicKey public_key;
33  memset(&public_key, 0, sizeof(public_key));
34
35  // DER encoding of the object identifier (OID) of the named curve P-256
36  // (1.2.840.10045.3.1.7). See RFC 6637 Section 11.
37  static const unsigned char p256_oid[] = {
38    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
39  };
40  public_key.keyType = ecKey;
41  public_key.u.ec.DEREncodedParams.type = siBuffer;
42  public_key.u.ec.DEREncodedParams.data = const_cast<unsigned char*>(p256_oid);
43  public_key.u.ec.DEREncodedParams.len = sizeof(p256_oid);
44
45  unsigned char key_buf[65];
46  key_buf[0] = 0x04;
47  memcpy(&key_buf[1], key.data(), key.size());
48  public_key.u.ec.publicValue.type = siBuffer;
49  public_key.u.ec.publicValue.data = key_buf;
50  public_key.u.ec.publicValue.len = sizeof(key_buf);
51
52  SECItem signature_item = {
53    siBuffer,
54    reinterpret_cast<unsigned char*>(const_cast<char*>(signature.data())),
55    static_cast<unsigned int>(signature.size())
56  };
57
58  unsigned char hash_buf[SHA256_LENGTH];
59  SECItem hash_item = { siBuffer, hash_buf, sizeof(hash_buf) };
60
61  HASHContext* sha256 = HASH_Create(HASH_AlgSHA256);
62  if (!sha256) {
63    return false;
64  }
65  HASH_Begin(sha256);
66  if (is_channel_id_signature) {
67    HASH_Update(sha256, reinterpret_cast<const unsigned char*>(kContextStr),
68                strlen(kContextStr) + 1);
69    HASH_Update(sha256,
70                reinterpret_cast<const unsigned char*>(kClientToServerStr),
71                strlen(kClientToServerStr) + 1);
72  }
73  HASH_Update(sha256,
74              reinterpret_cast<const unsigned char*>(signed_data.data()),
75              signed_data.size());
76  HASH_End(sha256, hash_buf, &hash_item.len, sizeof(hash_buf));
77  HASH_Destroy(sha256);
78
79  return PK11_Verify(&public_key, &signature_item, &hash_item, NULL) ==
80         SECSuccess;
81}
82
83}  // namespace net
84