Retrieve the authenticated user's e-mail from GAIA during SAML enrollment
[chromium-blink-merge.git] / crypto / signature_verifier_openssl.cc
bloba85f00b491ed8e479883f49e09227a28470c53c5
1 // Copyright (c) 2011 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.
5 #include "crypto/signature_verifier.h"
7 #include <openssl/evp.h>
8 #include <openssl/x509.h>
10 #include <vector>
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stl_util.h"
15 #include "crypto/openssl_util.h"
17 namespace crypto {
19 namespace {
21 const EVP_MD* ToOpenSSLDigest(SignatureVerifier::HashAlgorithm hash_alg) {
22 switch (hash_alg) {
23 case SignatureVerifier::SHA1:
24 return EVP_sha1();
25 case SignatureVerifier::SHA256:
26 return EVP_sha256();
28 return EVP_md_null();
31 } // namespace
33 struct SignatureVerifier::VerifyContext {
34 ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx;
37 SignatureVerifier::SignatureVerifier()
38 : verify_context_(NULL) {
41 SignatureVerifier::~SignatureVerifier() {
42 Reset();
45 bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
46 int signature_algorithm_len,
47 const uint8* signature,
48 int signature_len,
49 const uint8* public_key_info,
50 int public_key_info_len) {
51 OpenSSLErrStackTracer err_tracer(FROM_HERE);
52 ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free> algorithm(
53 d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len));
54 if (!algorithm.get())
55 return false;
56 int nid = OBJ_obj2nid(algorithm.get()->algorithm);
57 const EVP_MD* digest;
58 if (nid == NID_ecdsa_with_SHA1) {
59 digest = EVP_sha1();
60 } else if (nid == NID_ecdsa_with_SHA256) {
61 digest = EVP_sha256();
62 } else {
63 // This works for PKCS #1 v1.5 RSA signatures, but not for ECDSA
64 // signatures.
65 digest = EVP_get_digestbyobj(algorithm.get()->algorithm);
67 if (!digest)
68 return false;
70 return CommonInit(digest, signature, signature_len, public_key_info,
71 public_key_info_len, NULL);
74 bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg,
75 HashAlgorithm mask_hash_alg,
76 int salt_len,
77 const uint8* signature,
78 int signature_len,
79 const uint8* public_key_info,
80 int public_key_info_len) {
81 OpenSSLErrStackTracer err_tracer(FROM_HERE);
82 const EVP_MD* digest = ToOpenSSLDigest(hash_alg);
83 DCHECK(digest);
85 EVP_PKEY_CTX* pkey_ctx;
86 if (!CommonInit(digest, signature, signature_len, public_key_info,
87 public_key_info_len, &pkey_ctx)) {
88 return false;
91 int rv = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING);
92 if (rv != 1)
93 return false;
94 rv = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx,
95 ToOpenSSLDigest(mask_hash_alg));
96 if (rv != 1)
97 return false;
98 rv = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len);
99 return rv == 1;
102 void SignatureVerifier::VerifyUpdate(const uint8* data_part,
103 int data_part_len) {
104 DCHECK(verify_context_);
105 OpenSSLErrStackTracer err_tracer(FROM_HERE);
106 int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(),
107 data_part, data_part_len);
108 DCHECK_EQ(rv, 1);
111 bool SignatureVerifier::VerifyFinal() {
112 DCHECK(verify_context_);
113 OpenSSLErrStackTracer err_tracer(FROM_HERE);
114 int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(),
115 vector_as_array(&signature_),
116 signature_.size());
117 // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly.
118 DCHECK_GE(rv, -1);
119 Reset();
120 return rv == 1;
123 bool SignatureVerifier::CommonInit(const EVP_MD* digest,
124 const uint8* signature,
125 int signature_len,
126 const uint8* public_key_info,
127 int public_key_info_len,
128 EVP_PKEY_CTX** pkey_ctx) {
129 if (verify_context_)
130 return false;
132 verify_context_ = new VerifyContext;
134 signature_.assign(signature, signature + signature_len);
136 // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
137 char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info));
138 ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data,
139 public_key_info_len));
140 if (!bio.get())
141 return false;
143 ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key(
144 d2i_PUBKEY_bio(bio.get(), NULL));
145 if (!public_key.get())
146 return false;
148 verify_context_->ctx.reset(EVP_MD_CTX_create());
149 int rv = EVP_DigestVerifyInit(verify_context_->ctx.get(), pkey_ctx,
150 digest, NULL, public_key.get());
151 return rv == 1;
154 void SignatureVerifier::Reset() {
155 delete verify_context_;
156 verify_context_ = NULL;
157 signature_.clear();
160 } // namespace crypto