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 "crypto/ec_signature_creator_impl.h" 6 7#include <cryptohi.h> 8#include <pk11pub.h> 9#include <secerr.h> 10#include <sechash.h> 11#if defined(OS_POSIX) 12#include <unistd.h> 13#endif 14 15#include "base/logging.h" 16#include "crypto/ec_private_key.h" 17#include "crypto/nss_util.h" 18#include "crypto/scoped_nss_types.h" 19 20namespace crypto { 21 22namespace { 23 24SECStatus SignData(SECItem* result, 25 SECItem* input, 26 SECKEYPrivateKey* key, 27 HASH_HashType hash_type, 28 size_t* out_signature_len) { 29 if (key->keyType != ecKey) { 30 DLOG(FATAL) << "Should be using an EC key."; 31 PORT_SetError(SEC_ERROR_INVALID_ARGS); 32 return SECFailure; 33 } 34 35 // Hash the input. 36 std::vector<uint8> hash_data(HASH_ResultLen(hash_type)); 37 SECStatus rv = HASH_HashBuf( 38 hash_type, &hash_data[0], input->data, input->len); 39 if (rv != SECSuccess) 40 return rv; 41 SECItem hash = {siBuffer, &hash_data[0], 42 static_cast<unsigned int>(hash_data.size())}; 43 44 // Compute signature of hash. 45 int signature_len = PK11_SignatureLen(key); 46 std::vector<uint8> signature_data(signature_len); 47 SECItem sig = {siBuffer, &signature_data[0], 48 static_cast<unsigned int>(signature_len)}; 49 rv = PK11_Sign(key, &sig, &hash); 50 if (rv != SECSuccess) 51 return rv; 52 53 *out_signature_len = sig.len; 54 55 // DER encode the signature. 56 return DSAU_EncodeDerSigWithLen(result, &sig, sig.len); 57} 58 59} // namespace 60 61ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key) 62 : key_(key), 63 signature_len_(0) { 64 EnsureNSSInit(); 65} 66 67ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {} 68 69bool ECSignatureCreatorImpl::Sign(const uint8* data, 70 int data_len, 71 std::vector<uint8>* signature) { 72 // Data to be signed 73 SECItem secret; 74 secret.type = siBuffer; 75 secret.len = data_len; 76 secret.data = const_cast<unsigned char*>(data); 77 78 // SECItem to receive the output buffer. 79 SECItem result; 80 result.type = siBuffer; 81 result.len = 0; 82 result.data = NULL; 83 84 // Sign the secret data and save it to |result|. 85 SECStatus rv = 86 SignData(&result, &secret, key_->key(), HASH_AlgSHA256, &signature_len_); 87 if (rv != SECSuccess) { 88 DLOG(ERROR) << "DerSignData: " << PORT_GetError(); 89 return false; 90 } 91 92 // Copy the signed data into the output vector. 93 signature->assign(result.data, result.data + result.len); 94 SECITEM_FreeItem(&result, PR_FALSE /* only free |result.data| */); 95 return true; 96} 97 98bool ECSignatureCreatorImpl::DecodeSignature( 99 const std::vector<uint8>& der_sig, 100 std::vector<uint8>* out_raw_sig) { 101 SECItem der_sig_item; 102 der_sig_item.type = siBuffer; 103 der_sig_item.len = der_sig.size(); 104 der_sig_item.data = const_cast<uint8*>(&der_sig[0]); 105 106 SECItem* raw_sig = DSAU_DecodeDerSigToLen(&der_sig_item, signature_len_); 107 if (!raw_sig) 108 return false; 109 out_raw_sig->assign(raw_sig->data, raw_sig->data + raw_sig->len); 110 SECITEM_FreeItem(raw_sig, PR_TRUE /* free SECItem structure itself. */); 111 return true; 112} 113 114} // namespace crypto 115