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