• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/subtle/rsa_ssa_pss_sign_boringssl.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/memory/memory.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/types/span.h"
28 #include "openssl/evp.h"
29 #include "openssl/rsa.h"
30 #include "tink/internal/err_util.h"
31 #include "tink/internal/md_util.h"
32 #include "tink/internal/rsa_util.h"
33 #include "tink/internal/ssl_unique_ptr.h"
34 #include "tink/internal/util.h"
35 #include "tink/subtle/subtle_util.h"
36 #include "tink/util/status.h"
37 #include "tink/util/statusor.h"
38 
39 namespace crypto {
40 namespace tink {
41 namespace subtle {
42 namespace {
43 
44 // Computes an RSA-SSA PSS signature using `rsa_private_key` over `digest`;
45 // `digest` is the digest of the message to sign computed with `sig_md`,
46 // `mgf1_md` is the hash function for generating the mask (if nullptr, `sig_md`
47 // is used), and `salt_length` the salt length in bytes.
48 //
49 // This function is equivalent to BoringSSL's `RSA_sign_pss_mgf1`[1], and
50 // differs from it only in that it uses `RSA_private_encrypt` instead of
51 // `RSA_sign_raw`, because the latter is not defined in OpenSSL. In BoringSSL
52 // `RSA_private_encrypt` is essentially an alias for `RSA_sign_raw` [2].
53 //
54 // OpenSSL uses the same sequence of API calls [3].
55 //
56 // [1]https://github.com/google/boringssl/blob/master/crypto/fipsmodule/rsa/rsa.c#L557
57 // [2]https://github.com/google/boringssl/blob/master/crypto/fipsmodule/rsa/rsa.c#L315
58 // [3]https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_pmeth.c#L181
SslRsaSsaPssSign(RSA * rsa_private_key,absl::string_view digest,const EVP_MD * sig_md,const EVP_MD * mgf1_md,int32_t salt_length)59 util::StatusOr<std::string> SslRsaSsaPssSign(RSA* rsa_private_key,
60                                              absl::string_view digest,
61                                              const EVP_MD* sig_md,
62                                              const EVP_MD* mgf1_md,
63                                              int32_t salt_length) {
64   const int kHashSize = EVP_MD_size(sig_md);
65   // Make sure the size of the digest is correct.
66   if (digest.size() != kHashSize) {
67     return util::Status(absl::StatusCode::kInvalidArgument,
68                         absl::StrCat("Size of the digest doesn't match the one "
69                                      "of the hashing algorithm; expected ",
70                                      kHashSize, " got ", digest.size()));
71   }
72   const int kModulusSize = RSA_size(rsa_private_key);
73   std::vector<uint8_t> temporary_buffer(kModulusSize);
74   // This will write exactly kModulusSize bytes to temporary_buffer.
75   if (RSA_padding_add_PKCS1_PSS_mgf1(
76           /*rsa=*/rsa_private_key, /*EM=*/temporary_buffer.data(),
77           /*mHash=*/reinterpret_cast<const uint8_t*>(digest.data()),
78           /*Hash=*/sig_md,
79           /*mgf1Hash=*/mgf1_md,
80           /*sLen=*/salt_length) != 1) {
81     internal::GetSslErrors();
82     return util::Status(absl::StatusCode::kInternal,
83                         "RSA_padding_add_PKCS1_PSS_mgf1 failed.");
84   }
85   std::string signature;
86   ResizeStringUninitialized(&signature, kModulusSize);
87   int signature_length = RSA_private_encrypt(
88       /*flen=*/kModulusSize, /*from=*/temporary_buffer.data(),
89       /*to=*/reinterpret_cast<uint8_t*>(&signature[0]),
90       /*rsa=*/rsa_private_key,
91       /*padding=*/RSA_NO_PADDING);
92   if (signature_length < 0) {
93     internal::GetSslErrors();
94     return util::Status(absl::StatusCode::kInternal,
95                         "RSA_private_encrypt failed.");
96   }
97   signature.resize(signature_length);
98   return signature;
99 }
100 
101 }  // namespace
102 
New(const internal::RsaPrivateKey & private_key,const internal::RsaSsaPssParams & params)103 util::StatusOr<std::unique_ptr<PublicKeySign>> RsaSsaPssSignBoringSsl::New(
104     const internal::RsaPrivateKey& private_key,
105     const internal::RsaSsaPssParams& params) {
106   util::Status status =
107       internal::CheckFipsCompatibility<RsaSsaPssSignBoringSsl>();
108   if (!status.ok()) {
109     return status;
110   }
111 
112   // Check if the hash type is safe to use.
113   util::Status is_safe = internal::IsHashTypeSafeForSignature(params.sig_hash);
114   if (!is_safe.ok()) {
115     return is_safe;
116   }
117 
118   util::StatusOr<const EVP_MD*> sig_hash =
119       internal::EvpHashFromHashType(params.sig_hash);
120   if (!sig_hash.ok()) {
121     return sig_hash.status();
122   }
123 
124   util::StatusOr<const EVP_MD*> mgf1_hash =
125       internal::EvpHashFromHashType(params.mgf1_hash);
126   if (!mgf1_hash.ok()) {
127     return mgf1_hash.status();
128   }
129 
130   // The RSA modulus and exponent are checked as part of the conversion to
131   // internal::SslUniquePtr<RSA>.
132   util::StatusOr<internal::SslUniquePtr<RSA>> rsa =
133       internal::RsaPrivateKeyToRsa(private_key);
134   if (!rsa.ok()) {
135     return rsa.status();
136   }
137 
138   return {absl::WrapUnique(new RsaSsaPssSignBoringSsl(
139       *std::move(rsa), *sig_hash, *mgf1_hash, params.salt_length))};
140 }
141 
Sign(absl::string_view data) const142 util::StatusOr<std::string> RsaSsaPssSignBoringSsl::Sign(
143     absl::string_view data) const {
144   data = internal::EnsureStringNonNull(data);
145   util::StatusOr<std::string> digest = internal::ComputeHash(data, *sig_hash_);
146   if (!digest.ok()) {
147     return digest.status();
148   }
149 
150   util::StatusOr<std::string> signature = SslRsaSsaPssSign(
151       private_key_.get(), *digest, sig_hash_, mgf1_hash_, salt_length_);
152   if (!signature.ok()) {
153     return util::Status(absl::StatusCode::kInternal, "Signing failed.");
154   }
155   return signature;
156 }
157 
158 }  // namespace subtle
159 }  // namespace tink
160 }  // namespace crypto
161