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