1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <libcr51sign/libcr51sign.h>
18 #include <libcr51sign/libcr51sign_support.h>
19 #include <openssl/err.h>
20 #include <openssl/evp.h>
21 #include <openssl/pem.h>
22 #include <openssl/rsa.h>
23 #include <stdio.h>
24 
25 #ifdef __cplusplus
26 extern "C"
27 {
28 #endif
29 
30 #ifndef USER_PRINT
31 #define CPRINTS(ctx, ...) fprintf(stderr, __VA_ARGS__)
32 #endif
33 
34 // @func hash_init get ready to compute a hash
35 //
36 // @param[in] ctx - context struct
37 // @param[in] hash_type - type of hash function to use
38 //
39 // @return nonzero on error, zero on success
40 
41 int hash_init(const void* ctx, enum hash_type type)
42 {
43     struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
44     struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
45     hash_context->hash_type = type;
46     if (type == HASH_SHA2_256) // SHA256_Init returns 1
47         SHA256_Init(&hash_context->sha256_ctx);
48     else if (type == HASH_SHA2_512)
49         SHA512_Init(&hash_context->sha512_ctx);
50     else
51         return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
52 
53     return LIBCR51SIGN_SUCCESS;
54 }
55 
56 // @func hash_update add data to the hash
57 //
58 // @param[in] ctx - context struct
59 // @param[in] buf - data to add to hash
60 // @param[in] count - number of bytes of data to add
61 //
62 // @return nonzero on error, zero on success
63 
64 int hash_update(void* ctx, const uint8_t* data, size_t size)
65 {
66     if (size == 0)
67         return LIBCR51SIGN_SUCCESS;
68     struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
69     struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
70 
71     if (hash_context->hash_type == HASH_SHA2_256) // SHA256_Update returns 1
72         SHA256_Update(&hash_context->sha256_ctx, data, size);
73     else if (hash_context->hash_type == HASH_SHA2_512)
74         SHA512_Update(&hash_context->sha512_ctx, data, size);
75     else
76         return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
77 
78     return LIBCR51SIGN_SUCCESS;
79 }
80 
81 // @func hash_final finish hash calculation
82 //
83 // @param[in] ctx - context struct
84 // @param[out] hash - buffer to write hash to (guaranteed to be big enough)
85 //
86 // @return nonzero on error, zero on success
87 
88 int hash_final(void* ctx, uint8_t* hash)
89 {
90     int rv;
91     struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
92     struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
93 
94     if (hash_context->hash_type == HASH_SHA2_256)
95         rv = SHA256_Final(hash, &hash_context->sha256_ctx);
96     else if (hash_context->hash_type == HASH_SHA2_512)
97         rv = SHA512_Final(hash, &hash_context->sha512_ctx);
98     else
99         return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
100 
101     if (rv)
102         return LIBCR51SIGN_SUCCESS;
103     else
104         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
105 }
106 
107 // @func verify check that the signature is valid for given hashed data
108 //
109 // @param[in] ctx - context struct
110 // @param[in] scheme - type of signature, hash, etc.
111 // @param[in] sig - signature blob
112 // @param[in] sig_len - length of signature in bytes
113 // @param[in] data - pre-hashed data to verify
114 // @param[in] data_len - length of hashed data in bytes
115 //
116 // verify_signature expects RSA public key file path in ctx->key_ring
117 // @return nonzero on error, zero on success
118 
119 int verify_signature(const void* ctx, enum signature_scheme sig_scheme,
120                      const uint8_t* sig, size_t sig_len, const uint8_t* data,
121                      size_t data_len)
122 {
123     // By default returns error.
124     int rv = LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
125 
126     CPRINTS(ctx, "sig_len %zu sig: ", sig_len);
127     for (size_t i = 0; i < sig_len; i++)
128     {
129         CPRINTS(ctx, "%x", sig[i]);
130     }
131     CPRINTS(ctx, "\n");
132 
133     struct libcr51sign_ctx* lctx = (struct libcr51sign_ctx*)ctx;
134     FILE* fp = fopen(lctx->keyring, "r");
135     RSA *rsa = NULL, *pub_rsa = NULL;
136     EVP_PKEY* pkey = NULL;
137     BIO* bio = BIO_new(BIO_s_mem());
138     if (!fp)
139     {
140         CPRINTS(ctx, "fopen failed\n");
141         goto clean_up;
142     }
143 
144     pkey = PEM_read_PUBKEY(fp, 0, 0, 0);
145     if (!pkey)
146     {
147         CPRINTS(ctx, "Read public key failed\n");
148         goto clean_up;
149     }
150 
151     rsa = EVP_PKEY_get1_RSA(pkey);
152     if (!rsa)
153     {
154         goto clean_up;
155     }
156     pub_rsa = RSAPublicKey_dup(rsa);
157     if (!RSA_print(bio, pub_rsa, 2))
158     {
159         CPRINTS(ctx, "RSA print failed\n");
160     }
161     if (!pub_rsa)
162     {
163         CPRINTS(ctx, "no pub RSA\n");
164         goto clean_up;
165     }
166     CPRINTS(ctx, "public RSA\n");
167     char buffer[1024];
168     while (BIO_read(bio, buffer, sizeof(buffer) - 1) > 0)
169     {
170         CPRINTS(ctx, " %s", buffer);
171     }
172     enum hash_type hash_type;
173     rv = get_hash_type_from_signature(sig_scheme, &hash_type);
174     if (rv != LIBCR51SIGN_SUCCESS)
175     {
176         CPRINTS(ctx, "Invalid hash_type!\n");
177         goto clean_up;
178     }
179     int hash_nid = -1;
180     if (hash_type == HASH_SHA2_256)
181     {
182         hash_nid = NID_sha256;
183     }
184     else if (hash_type == HASH_SHA2_512)
185     {
186         hash_nid = NID_sha512;
187     }
188     else
189     {
190         rv = LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
191         goto clean_up;
192     }
193 
194     int ret = RSA_verify(hash_nid, data, data_len, sig, sig_len, pub_rsa);
195     // OpenSSL RSA_verify returns 1 on success and 0 on failure
196     if (!ret)
197     {
198         CPRINTS(ctx, "OPENSSL_ERROR: %s\n",
199                 ERR_error_string(ERR_get_error(), NULL));
200         rv = LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
201         goto clean_up;
202     }
203     rv = LIBCR51SIGN_SUCCESS;
204     CPRINTS(ctx, "sig: ");
205     for (size_t i = 0; i < sig_len; i++)
206     {
207         CPRINTS(ctx, "%x", sig[i]);
208     }
209     CPRINTS(ctx, "\n");
210 
211     CPRINTS(ctx, "data: ");
212     for (size_t i = 0; i < data_len; i++)
213     {
214         CPRINTS(ctx, "%x", data[i]);
215     }
216     CPRINTS(ctx, "\n");
217 
218     const unsigned rsa_size = RSA_size(pub_rsa);
219     CPRINTS(ctx, "rsa size %d sig_len %d\n", rsa_size, (uint32_t)sig_len);
220 
221 clean_up:
222     if (fp)
223     {
224         fclose(fp);
225     }
226     EVP_PKEY_free(pkey);
227     RSA_free(rsa);
228     RSA_free(pub_rsa);
229     BIO_free(bio);
230     return rv;
231 }
232 
233 #ifdef __cplusplus
234 } //  extern "C"
235 #endif
236