1 /*!
2  * Copyrights
3  *
4  * Portions created or assigned to Cisco Systems, Inc. are
5  * Copyright (c) 2014-2016 Cisco Systems, Inc.  All Rights Reserved.
6  */
7 
8 #include <cjose/base64.h>
9 #include <cjose/header.h>
10 #include <cjose/jws.h>
11 #include <cjose/jwk.h>
12 #include <cjose/util.h>
13 
14 #include <string.h>
15 #include <assert.h>
16 #include <openssl/evp.h>
17 #include <openssl/rsa.h>
18 #include <openssl/err.h>
19 #include <openssl/hmac.h>
20 
21 #include "include/jwk_int.h"
22 #include "include/header_int.h"
23 #include "include/jws_int.h"
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 static bool _cjose_jws_build_dig_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
27 
28 static bool _cjose_jws_build_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
29 
30 static bool _cjose_jws_build_dig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
31 
32 static bool _cjose_jws_verify_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
33 
34 static bool _cjose_jws_build_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
35 
36 static bool _cjose_jws_verify_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
37 
38 static bool _cjose_jws_build_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
39 
40 static bool _cjose_jws_verify_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
41 
42 static bool _cjose_jws_build_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
43 
44 static bool _cjose_jws_verify_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err);
45 
46 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_hdr(cjose_jws_t * jws,cjose_header_t * header,cjose_err * err)47 static bool _cjose_jws_build_hdr(cjose_jws_t *jws, cjose_header_t *header, cjose_err *err)
48 {
49     // save header object as part of the JWS (and incr. refcount)
50     jws->hdr = (json_t *)header;
51     json_incref(jws->hdr);
52 
53     // base64url encode the header
54     char *hdr_str = json_dumps(jws->hdr, JSON_ENCODE_ANY | JSON_PRESERVE_ORDER);
55     if (NULL == hdr_str)
56     {
57         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
58         return false;
59     }
60     if (!cjose_base64url_encode((const uint8_t *)hdr_str, strlen(hdr_str), &jws->hdr_b64u, &jws->hdr_b64u_len, err))
61     {
62         free(hdr_str);
63         return false;
64     }
65     free(hdr_str);
66 
67     return true;
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_validate_hdr(cjose_jws_t * jws,cjose_err * err)71 static bool _cjose_jws_validate_hdr(cjose_jws_t *jws, cjose_err *err)
72 {
73     // make sure we have an alg header
74     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
75     if ((NULL == alg_obj) || (!json_is_string(alg_obj)))
76     {
77         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
78         return false;
79     }
80     const char *alg = json_string_value(alg_obj);
81 
82     if ((strcmp(alg, CJOSE_HDR_ALG_PS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
83         || (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0))
84     {
85         jws->fns.digest = _cjose_jws_build_dig_sha;
86         jws->fns.sign = _cjose_jws_build_sig_ps;
87         jws->fns.verify = _cjose_jws_verify_sig_ps;
88     }
89     else if ((strcmp(alg, CJOSE_HDR_ALG_RS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0)
90              || (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0))
91     {
92         jws->fns.digest = _cjose_jws_build_dig_sha;
93         jws->fns.sign = _cjose_jws_build_sig_rs;
94         jws->fns.verify = _cjose_jws_verify_sig_rs;
95     }
96     else if ((strcmp(alg, CJOSE_HDR_ALG_HS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_HS384) == 0)
97              || (strcmp(alg, CJOSE_HDR_ALG_HS512) == 0))
98     {
99         jws->fns.digest = _cjose_jws_build_dig_hmac_sha;
100         jws->fns.sign = _cjose_jws_build_sig_hmac_sha;
101         jws->fns.verify = _cjose_jws_verify_sig_hmac_sha;
102     }
103     else if ((strcmp(alg, CJOSE_HDR_ALG_ES256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_ES384) == 0)
104              || (strcmp(alg, CJOSE_HDR_ALG_ES512) == 0))
105     {
106         jws->fns.digest = _cjose_jws_build_dig_sha;
107         jws->fns.sign = _cjose_jws_build_sig_ec;
108         jws->fns.verify = _cjose_jws_verify_sig_ec;
109     }
110     else
111     {
112         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
113         return false;
114     }
115 
116     return true;
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_dat(cjose_jws_t * jws,const uint8_t * plaintext,size_t plaintext_len,cjose_err * err)120 static bool _cjose_jws_build_dat(cjose_jws_t *jws, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err)
121 {
122     // copy plaintext data
123     jws->dat_len = plaintext_len;
124     jws->dat = (uint8_t *)cjose_get_alloc()(jws->dat_len);
125     if (NULL == jws->dat)
126     {
127         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
128         return false;
129     }
130     memcpy(jws->dat, plaintext, jws->dat_len);
131 
132     // base64url encode data
133     if (!cjose_base64url_encode((const uint8_t *)plaintext, plaintext_len, &jws->dat_b64u, &jws->dat_b64u_len, err))
134     {
135         return false;
136     }
137 
138     return true;
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_dig_sha(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)142 static bool _cjose_jws_build_dig_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
143 {
144     bool retval = false;
145     EVP_MD_CTX *ctx = NULL;
146 
147     // make sure we have an alg header
148     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
149     if (NULL == alg_obj)
150     {
151         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
152         return false;
153     }
154     const char *alg = json_string_value(alg_obj);
155 
156     // build digest using SHA-256/384/512 digest algorithm
157     const EVP_MD *digest_alg = NULL;
158     if ((strcmp(alg, CJOSE_HDR_ALG_RS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
159         || (strcmp(alg, CJOSE_HDR_ALG_ES256) == 0))
160         digest_alg = EVP_sha256();
161     else if ((strcmp(alg, CJOSE_HDR_ALG_RS384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
162              || (strcmp(alg, CJOSE_HDR_ALG_ES384) == 0))
163         digest_alg = EVP_sha384();
164     else if ((strcmp(alg, CJOSE_HDR_ALG_RS512) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
165              || (strcmp(alg, CJOSE_HDR_ALG_ES512) == 0))
166         digest_alg = EVP_sha512();
167 
168     if (NULL == digest_alg)
169     {
170         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
171         goto _cjose_jws_build_dig_sha_cleanup;
172     }
173 
174     // allocate buffer for digest
175     jws->dig_len = EVP_MD_size(digest_alg);
176     jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len);
177     if (NULL == jws->dig)
178     {
179         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
180         goto _cjose_jws_build_dig_sha_cleanup;
181     }
182 
183     // instantiate and initialize a new mac digest context
184     ctx = EVP_MD_CTX_create();
185     if (NULL == ctx)
186     {
187         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
188         goto _cjose_jws_build_dig_sha_cleanup;
189     }
190     EVP_MD_CTX_init(ctx);
191 
192     // create digest as DIGEST(B64U(HEADER).B64U(DATA))
193     if (EVP_DigestInit_ex(ctx, digest_alg, NULL) != 1)
194     {
195         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
196         goto _cjose_jws_build_dig_sha_cleanup;
197     }
198     if (EVP_DigestUpdate(ctx, jws->hdr_b64u, jws->hdr_b64u_len) != 1)
199     {
200         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
201         goto _cjose_jws_build_dig_sha_cleanup;
202     }
203     if (EVP_DigestUpdate(ctx, ".", 1) != 1)
204     {
205         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
206         goto _cjose_jws_build_dig_sha_cleanup;
207     }
208     if (EVP_DigestUpdate(ctx, jws->dat_b64u, jws->dat_b64u_len) != 1)
209     {
210         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
211         goto _cjose_jws_build_dig_sha_cleanup;
212     }
213     if (EVP_DigestFinal_ex(ctx, jws->dig, NULL) != 1)
214     {
215         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
216         goto _cjose_jws_build_dig_sha_cleanup;
217     }
218 
219     // if we got this far - success
220     retval = true;
221 
222 _cjose_jws_build_dig_sha_cleanup:
223     if (NULL != ctx)
224     {
225         EVP_MD_CTX_destroy(ctx);
226     }
227 
228     return retval;
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_dig_hmac_sha(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)232 static bool _cjose_jws_build_dig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
233 {
234     bool retval = false;
235     HMAC_CTX *ctx = NULL;
236 
237     // make sure we have an alg header
238     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
239     if (NULL == alg_obj)
240     {
241         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
242         return false;
243     }
244     const char *alg = json_string_value(alg_obj);
245 
246     // build digest using SHA-256/384/512 digest algorithm
247     const EVP_MD *digest_alg = NULL;
248     if (strcmp(alg, CJOSE_HDR_ALG_HS256) == 0)
249         digest_alg = EVP_sha256();
250     else if (strcmp(alg, CJOSE_HDR_ALG_HS384) == 0)
251         digest_alg = EVP_sha384();
252     else if (strcmp(alg, CJOSE_HDR_ALG_HS512) == 0)
253         digest_alg = EVP_sha512();
254 
255     if (NULL == digest_alg)
256     {
257         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
258         goto _cjose_jws_build_dig_hmac_sha_cleanup;
259     }
260 
261     // allocate buffer for digest
262     jws->dig_len = EVP_MD_size(digest_alg);
263     jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len);
264     if (NULL == jws->dig)
265     {
266         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
267         goto _cjose_jws_build_dig_hmac_sha_cleanup;
268     }
269 
270 // instantiate and initialize a new mac digest context
271 #if defined(CJOSE_OPENSSL_11X)
272     ctx = HMAC_CTX_new();
273 #else
274     ctx = cjose_get_alloc()(sizeof(HMAC_CTX));
275 #endif
276     if (NULL == ctx)
277     {
278         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
279         goto _cjose_jws_build_dig_hmac_sha_cleanup;
280     }
281 
282 #if !defined(CJOSE_OPENSSL_11X)
283     HMAC_CTX_init(ctx);
284 #endif
285 
286     // create digest as DIGEST(B64U(HEADER).B64U(DATA))
287     if (HMAC_Init_ex(ctx, jwk->keydata, jwk->keysize / 8, digest_alg, NULL) != 1)
288     {
289         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
290         goto _cjose_jws_build_dig_hmac_sha_cleanup;
291     }
292     if (HMAC_Update(ctx, (const unsigned char *)jws->hdr_b64u, jws->hdr_b64u_len) != 1)
293     {
294         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
295         goto _cjose_jws_build_dig_hmac_sha_cleanup;
296     }
297     if (HMAC_Update(ctx, (const unsigned char *)".", 1) != 1)
298     {
299         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
300         goto _cjose_jws_build_dig_hmac_sha_cleanup;
301     }
302     if (HMAC_Update(ctx, (const unsigned char *)jws->dat_b64u, jws->dat_b64u_len) != 1)
303     {
304         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
305         goto _cjose_jws_build_dig_hmac_sha_cleanup;
306     }
307     if (HMAC_Final(ctx, jws->dig, NULL) != 1)
308     {
309         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
310         goto _cjose_jws_build_dig_hmac_sha_cleanup;
311     }
312 
313     // if we got this far - success
314     retval = true;
315 
316 _cjose_jws_build_dig_hmac_sha_cleanup:
317     if (NULL != ctx)
318     {
319 #if defined(CJOSE_OPENSSL_11X)
320         HMAC_CTX_free(ctx);
321 #else
322         HMAC_CTX_cleanup(ctx);
323         cjose_get_dealloc()(ctx);
324 #endif
325     }
326 
327     return retval;
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_sig_ps(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)331 static bool _cjose_jws_build_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
332 {
333     bool retval = false;
334     uint8_t *em = NULL;
335     size_t em_len = 0;
336 
337     // ensure jwk is private RSA
338     if (jwk->kty != CJOSE_JWK_KTY_RSA)
339     {
340         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
341         goto _cjose_jws_build_sig_ps_cleanup;
342     }
343     RSA *rsa = (RSA *)jwk->keydata;
344     BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
345     _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
346     if (!rsa || !rsa_e || !rsa_n || !rsa_d)
347     {
348         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
349         return false;
350     }
351 
352     // make sure we have an alg header
353     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
354     if (NULL == alg_obj)
355     {
356         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
357         return false;
358     }
359     const char *alg = json_string_value(alg_obj);
360 
361     // build digest using SHA-256/384/512 digest algorithm
362     const EVP_MD *digest_alg = NULL;
363     if (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
364         digest_alg = EVP_sha256();
365     else if (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
366         digest_alg = EVP_sha384();
367     else if (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
368         digest_alg = EVP_sha512();
369 
370     if (NULL == digest_alg)
371     {
372         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
373         goto _cjose_jws_build_sig_ps_cleanup;
374     }
375 
376     // apply EMSA-PSS encoding (RFC-3447, 8.1.1, step 1)
377     // (RSA_padding_add_PKCS1_PSS includes PKCS1_MGF1, -1 => saltlen = hashlen)
378     em_len = RSA_size((RSA *)jwk->keydata);
379     em = (uint8_t *)cjose_get_alloc()(em_len);
380     if (NULL == em)
381     {
382         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
383         goto _cjose_jws_build_sig_ps_cleanup;
384     }
385     if (RSA_padding_add_PKCS1_PSS((RSA *)jwk->keydata, em, jws->dig, digest_alg, -1) != 1)
386     {
387         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
388         goto _cjose_jws_build_sig_ps_cleanup;
389     }
390 
391     // sign the digest (RFC-3447, 8.1.1, step 2)
392     jws->sig_len = em_len;
393     jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
394     if (NULL == jws->sig)
395     {
396         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
397         goto _cjose_jws_build_sig_ps_cleanup;
398     }
399 
400     if (RSA_private_encrypt(em_len, em, jws->sig, (RSA *)jwk->keydata, RSA_NO_PADDING) != jws->sig_len)
401     {
402         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
403         goto _cjose_jws_build_sig_ps_cleanup;
404     }
405 
406     // base64url encode signed digest
407     if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
408     {
409         goto _cjose_jws_build_sig_ps_cleanup;
410     }
411 
412     // if we got this far - success
413     retval = true;
414 
415 _cjose_jws_build_sig_ps_cleanup:
416     cjose_get_dealloc()(em);
417 
418     return retval;
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_sig_rs(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)422 static bool _cjose_jws_build_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
423 {
424     // ensure jwk is private RSA
425     if (jwk->kty != CJOSE_JWK_KTY_RSA)
426     {
427         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
428         return false;
429     }
430     RSA *rsa = (RSA *)jwk->keydata;
431     BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
432     _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
433     if (!rsa || !rsa_e || !rsa_n || !rsa_d)
434     {
435         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
436         return false;
437     }
438 
439     // allocate buffer for signature
440     jws->sig_len = RSA_size((RSA *)jwk->keydata);
441     jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
442     if (NULL == jws->sig)
443     {
444         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
445         return false;
446     }
447 
448     // make sure we have an alg header
449     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
450     if (NULL == alg_obj)
451     {
452         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
453         return false;
454     }
455     const char *alg = json_string_value(alg_obj);
456 
457     // build digest using SHA-256/384/512 digest algorithm
458     int digest_alg = -1;
459     if (strcmp(alg, CJOSE_HDR_ALG_RS256) == 0)
460         digest_alg = NID_sha256;
461     else if (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0)
462         digest_alg = NID_sha384;
463     else if (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0)
464         digest_alg = NID_sha512;
465     if (-1 == digest_alg)
466     {
467         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
468         return false;
469     }
470 
471     unsigned int siglen;
472     if (RSA_sign(digest_alg, jws->dig, jws->dig_len, jws->sig, &siglen, (RSA *)jwk->keydata) != 1)
473     {
474         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
475         return false;
476     }
477     jws->sig_len = siglen;
478 
479     // base64url encode signed digest
480     if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
481     {
482         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
483         return false;
484     }
485 
486     return true;
487 }
488 
_cjose_jws_build_sig_hmac_sha(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)489 static bool _cjose_jws_build_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
490 {
491     // ensure jwk is OCT
492     if (jwk->kty != CJOSE_JWK_KTY_OCT)
493     {
494         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
495         return false;
496     }
497 
498     // allocate buffer for signature
499     jws->sig_len = jws->dig_len;
500     jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
501     if (NULL == jws->sig)
502     {
503         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
504         return false;
505     }
506 
507     memcpy(jws->sig, jws->dig, jws->sig_len);
508 
509     // base64url encode signed digest
510     if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
511     {
512         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
513         return false;
514     }
515 
516     return true;
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_sig_ec(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)520 static bool _cjose_jws_build_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
521 {
522     bool retval = false;
523 
524     // ensure jwk is EC
525     if (jwk->kty != CJOSE_JWK_KTY_EC)
526     {
527         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
528         return false;
529     }
530 
531     ec_keydata *keydata = (ec_keydata *)jwk->keydata;
532     EC_KEY *ec = keydata->key;
533 
534     ECDSA_SIG *ecdsa_sig = ECDSA_do_sign(jws->dig, jws->dig_len, ec);
535     if (NULL == ecdsa_sig)
536     {
537         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
538         goto _cjose_jws_build_sig_ec_cleanup;
539     }
540 
541     // allocate buffer for signature
542     switch (keydata->crv)
543     {
544     case CJOSE_JWK_EC_P_256:
545         jws->sig_len = 32 * 2;
546         break;
547     case CJOSE_JWK_EC_P_384:
548         jws->sig_len = 48 * 2;
549         break;
550     case CJOSE_JWK_EC_P_521:
551         jws->sig_len = 66 * 2;
552         break;
553     case CJOSE_JWK_EC_INVALID:
554         jws->sig_len = 0;
555         break;
556     }
557 
558     jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
559     if (NULL == jws->sig)
560     {
561         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
562         goto _cjose_jws_build_sig_ec_cleanup;
563     }
564 
565     memset(jws->sig, 0, jws->sig_len);
566 
567     const BIGNUM *pr, *ps;
568 #if defined(CJOSE_OPENSSL_11X)
569     ECDSA_SIG_get0(ecdsa_sig, &pr, &ps);
570 #else
571     pr = ecdsa_sig->r;
572     ps = ecdsa_sig->s;
573 #endif
574 
575     int rlen = BN_num_bytes(pr);
576     int slen = BN_num_bytes(ps);
577     BN_bn2bin(pr, jws->sig + jws->sig_len / 2 - rlen);
578     BN_bn2bin(ps, jws->sig + jws->sig_len - slen);
579 
580     // base64url encode signed digest
581     if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
582     {
583         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
584         goto _cjose_jws_build_sig_ec_cleanup;
585     }
586 
587     retval = true;
588 
589 _cjose_jws_build_sig_ec_cleanup:
590     if (ecdsa_sig)
591         ECDSA_SIG_free(ecdsa_sig);
592 
593     return retval;
594 }
595 
596 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_build_cser(cjose_jws_t * jws,cjose_err * err)597 static bool _cjose_jws_build_cser(cjose_jws_t *jws, cjose_err *err)
598 {
599     // both sign and import should be setting these - but check just in case
600     if (NULL == jws->hdr_b64u || NULL == jws->dat_b64u || NULL == jws->sig_b64u)
601     {
602         return false;
603     }
604 
605     // compute length of compact serialization
606     jws->cser_len = jws->hdr_b64u_len + jws->dat_b64u_len + jws->sig_b64u_len + 3;
607 
608     // allocate buffer for compact serialization
609     assert(NULL == jws->cser);
610     jws->cser = (char *)cjose_get_alloc()(jws->cser_len);
611     if (NULL == jws->cser)
612     {
613         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
614         return false;
615     }
616 
617     // build the compact serialization
618     snprintf(jws->cser, jws->cser_len, "%s.%s.%s", jws->hdr_b64u, jws->dat_b64u, jws->sig_b64u);
619 
620     return true;
621 }
622 
623 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_sign(const cjose_jwk_t * jwk,cjose_header_t * protected_header,const uint8_t * plaintext,size_t plaintext_len,cjose_err * err)624 cjose_jws_t *cjose_jws_sign(
625     const cjose_jwk_t *jwk, cjose_header_t *protected_header, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err)
626 {
627     cjose_jws_t *jws = NULL;
628 
629     if (NULL == jwk || NULL == protected_header || NULL == plaintext)
630     {
631         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
632         return NULL;
633     }
634 
635     // allocate and initialize JWS
636     jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t));
637     if (NULL == jws)
638     {
639         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
640         return NULL;
641     }
642     memset(jws, 0, sizeof(cjose_jws_t));
643 
644     // build JWS header
645     if (!_cjose_jws_build_hdr(jws, protected_header, err))
646     {
647         cjose_jws_release(jws);
648         return NULL;
649     }
650 
651     // validate JWS header
652     if (!_cjose_jws_validate_hdr(jws, err))
653     {
654         cjose_jws_release(jws);
655         return NULL;
656     }
657 
658     // build the JWS data segment
659     if (!_cjose_jws_build_dat(jws, plaintext, plaintext_len, err))
660     {
661         cjose_jws_release(jws);
662         return NULL;
663     }
664 
665     // build JWS digest (hashed signing input value)
666     if (!jws->fns.digest(jws, jwk, err))
667     {
668         cjose_jws_release(jws);
669         return NULL;
670     }
671 
672     // sign the JWS digest
673     if (!jws->fns.sign(jws, jwk, err))
674     {
675         cjose_jws_release(jws);
676         return NULL;
677     }
678 
679     // build JWS compact serialization
680     if (!_cjose_jws_build_cser(jws, err))
681     {
682         cjose_jws_release(jws);
683         return NULL;
684     }
685 
686     return jws;
687 }
688 
689 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_release(cjose_jws_t * jws)690 void cjose_jws_release(cjose_jws_t *jws)
691 {
692     if (NULL == jws)
693     {
694         return;
695     }
696 
697     if (NULL != jws->hdr)
698     {
699         json_decref(jws->hdr);
700     }
701 
702     cjose_get_dealloc()(jws->hdr_b64u);
703     cjose_get_dealloc()(jws->dat);
704     cjose_get_dealloc()(jws->dat_b64u);
705     cjose_get_dealloc()(jws->dig);
706     cjose_get_dealloc()(jws->sig);
707     cjose_get_dealloc()(jws->sig_b64u);
708     cjose_get_dealloc()(jws->cser);
709     cjose_get_dealloc()(jws);
710 }
711 
712 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_export(cjose_jws_t * jws,const char ** compact,cjose_err * err)713 bool cjose_jws_export(cjose_jws_t *jws, const char **compact, cjose_err *err)
714 {
715     if (NULL == jws || NULL == compact)
716     {
717         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
718         return false;
719     }
720 
721     if (NULL == jws->cser)
722     {
723         _cjose_jws_build_cser(jws, err);
724     }
725 
726     *compact = jws->cser;
727     return true;
728 }
729 
730 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_strcpy(char ** dst,const char * src,int len,cjose_err * err)731 static bool _cjose_jws_strcpy(char **dst, const char *src, int len, cjose_err *err)
732 {
733     *dst = (char *)cjose_get_alloc()(len + 1);
734     if (NULL == dst)
735     {
736         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
737         return false;
738     }
739 
740     strncpy(*dst, src, len);
741     (*dst)[len] = 0;
742 
743     return true;
744 }
745 
746 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_import(const char * cser,size_t cser_len,cjose_err * err)747 cjose_jws_t *cjose_jws_import(const char *cser, size_t cser_len, cjose_err *err)
748 {
749     cjose_jws_t *jws = NULL;
750     size_t len = 0;
751 
752     if (NULL == cser)
753     {
754         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
755         return NULL;
756     }
757 
758     // allocate and initialize a new JWS object
759     jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t));
760     if (NULL == jws)
761     {
762         CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
763         return NULL;
764     }
765     memset(jws, 0, sizeof(cjose_jws_t));
766 
767     // find the indexes of the dots
768     int idx = 0;
769     int d[2] = { 0, 0 };
770     for (int i = 0; i < cser_len && idx < 2; ++i)
771     {
772         if (cser[i] == '.')
773         {
774             d[idx++] = i;
775         }
776     }
777 
778     // fail if we didn't find both dots
779     if (0 == d[1])
780     {
781         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
782         cjose_jws_release(jws);
783         return NULL;
784     }
785 
786     // copy and decode header b64u segment
787     uint8_t *hdr_str = NULL;
788     jws->hdr_b64u_len = d[0];
789     _cjose_jws_strcpy(&jws->hdr_b64u, cser, jws->hdr_b64u_len, err);
790     if (!cjose_base64url_decode(jws->hdr_b64u, jws->hdr_b64u_len, &hdr_str, &len, err) || NULL == hdr_str)
791     {
792         cjose_jws_release(jws);
793         return NULL;
794     }
795 
796     // deserialize JSON header
797     jws->hdr = json_loadb((const char *)hdr_str, len, 0, NULL);
798     cjose_get_dealloc()(hdr_str);
799     if (NULL == jws->hdr)
800     {
801         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
802         cjose_jws_release(jws);
803         return NULL;
804     }
805 
806     // validate the JSON header segment
807     if (!_cjose_jws_validate_hdr(jws, err))
808     {
809         // make an exception for alg=none so that it will import/parse but not sign/verify
810         json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
811         if (NULL == alg_obj)
812         {
813             CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
814             return NULL;
815         }
816         const char *alg = json_string_value(alg_obj);
817         if ((!alg) || (strcmp(alg, CJOSE_HDR_ALG_NONE) != 0))
818         {
819             CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
820             cjose_jws_release(jws);
821             return NULL;
822         }
823     }
824 
825     // copy and b64u decode data segment
826     jws->dat_b64u_len = d[1] - d[0] - 1;
827     _cjose_jws_strcpy(&jws->dat_b64u, cser + d[0] + 1, jws->dat_b64u_len, err);
828     if (!cjose_base64url_decode(jws->dat_b64u, jws->dat_b64u_len, &jws->dat, &jws->dat_len, err))
829     {
830         cjose_jws_release(jws);
831         return NULL;
832     }
833 
834     // copy and b64u decode signature segment
835     jws->sig_b64u_len = cser_len - d[1] - 1;
836     _cjose_jws_strcpy(&jws->sig_b64u, cser + d[1] + 1, jws->sig_b64u_len, err);
837     if (!cjose_base64url_decode(jws->sig_b64u, jws->sig_b64u_len, &jws->sig, &jws->sig_len, err))
838     {
839         cjose_jws_release(jws);
840         return NULL;
841     }
842 
843     return jws;
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_verify_sig_ps(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)847 static bool _cjose_jws_verify_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
848 {
849     bool retval = false;
850     uint8_t *em = NULL;
851     size_t em_len = 0;
852 
853     // ensure jwk is RSA
854     if (jwk->kty != CJOSE_JWK_KTY_RSA)
855     {
856         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
857         goto _cjose_jws_verify_sig_ps_cleanup;
858     }
859 
860     // make sure we have an alg header
861     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
862     if (NULL == alg_obj)
863     {
864         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
865         return false;
866     }
867     const char *alg = json_string_value(alg_obj);
868 
869     // build digest using SHA-256/384/512 digest algorithm
870     const EVP_MD *digest_alg = NULL;
871     if (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
872         digest_alg = EVP_sha256();
873     else if (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
874         digest_alg = EVP_sha384();
875     else if (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
876         digest_alg = EVP_sha512();
877 
878     if (NULL == digest_alg)
879     {
880         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
881         goto _cjose_jws_verify_sig_ps_cleanup;
882     }
883 
884     // allocate buffer for encoded message
885     em_len = RSA_size((RSA *)jwk->keydata);
886     em = (uint8_t *)cjose_get_alloc()(em_len);
887     if (NULL == em)
888     {
889         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
890         goto _cjose_jws_verify_sig_ps_cleanup;
891     }
892 
893     // decrypt signature
894     if (RSA_public_decrypt(jws->sig_len, jws->sig, em, (RSA *)jwk->keydata, RSA_NO_PADDING) != em_len)
895     {
896         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
897         goto _cjose_jws_verify_sig_ps_cleanup;
898     }
899 
900     // verify decrypted signature data against PSS encoded digest
901     if (RSA_verify_PKCS1_PSS((RSA *)jwk->keydata, jws->dig, digest_alg, em, -1) != 1)
902     {
903         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
904         goto _cjose_jws_verify_sig_ps_cleanup;
905     }
906 
907     // if we got this far - success
908     retval = true;
909 
910 _cjose_jws_verify_sig_ps_cleanup:
911     cjose_get_dealloc()(em);
912 
913     return retval;
914 }
915 
916 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_verify_sig_rs(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)917 static bool _cjose_jws_verify_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
918 {
919     bool retval = false;
920 
921     // ensure jwk is RSA
922     if (jwk->kty != CJOSE_JWK_KTY_RSA)
923     {
924         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
925         goto _cjose_jws_verify_sig_rs_cleanup;
926     }
927 
928     // make sure we have an alg header
929     json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
930     if (NULL == alg_obj)
931     {
932         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
933         return false;
934     }
935     const char *alg = json_string_value(alg_obj);
936 
937     // build digest using SHA-256/384/512 digest algorithm
938     int digest_alg = -1;
939     if (strcmp(alg, CJOSE_HDR_ALG_RS256) == 0)
940         digest_alg = NID_sha256;
941     else if (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0)
942         digest_alg = NID_sha384;
943     else if (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0)
944         digest_alg = NID_sha512;
945     if (-1 == digest_alg)
946     {
947         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
948         goto _cjose_jws_verify_sig_rs_cleanup;
949     }
950 
951     if (RSA_verify(digest_alg, jws->dig, jws->dig_len, jws->sig, jws->sig_len, (RSA *)jwk->keydata) != 1)
952     {
953         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
954         goto _cjose_jws_verify_sig_rs_cleanup;
955     }
956 
957     // if we got this far - success
958     retval = true;
959 
960 _cjose_jws_verify_sig_rs_cleanup:
961 
962     return retval;
963 }
964 
965 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_verify_sig_hmac_sha(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)966 static bool _cjose_jws_verify_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
967 {
968     bool retval = false;
969 
970     // ensure jwk is OCT
971     if (jwk->kty != CJOSE_JWK_KTY_OCT)
972     {
973         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
974         goto _cjose_jws_verify_sig_hmac_sha_cleanup;
975     }
976 
977     // verify decrypted digest matches computed digest
978     if ((cjose_const_memcmp(jws->dig, jws->sig, jws->dig_len) != 0) || (jws->sig_len != jws->dig_len))
979     {
980         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
981         goto _cjose_jws_verify_sig_hmac_sha_cleanup;
982     }
983 
984     // if we got this far - success
985     retval = true;
986 
987 _cjose_jws_verify_sig_hmac_sha_cleanup:
988 
989     return retval;
990 }
991 
992 ////////////////////////////////////////////////////////////////////////////////
_cjose_jws_verify_sig_ec(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)993 static bool _cjose_jws_verify_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
994 {
995     bool retval = false;
996 
997     // ensure jwk is EC
998     if (jwk->kty != CJOSE_JWK_KTY_EC)
999     {
1000         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1001         return false;
1002     }
1003 
1004     ec_keydata *keydata = (ec_keydata *)jwk->keydata;
1005     EC_KEY *ec = keydata->key;
1006 
1007     ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new();
1008     int key_len = jws->sig_len / 2;
1009 
1010 #if defined(CJOSE_OPENSSL_11X)
1011     BIGNUM *pr = BN_new(), *ps = BN_new();
1012     BN_bin2bn(jws->sig, key_len, pr);
1013     BN_bin2bn(jws->sig + key_len, key_len, ps);
1014     ECDSA_SIG_set0(ecdsa_sig, pr, ps);
1015 #else
1016     BN_bin2bn(jws->sig, key_len, ecdsa_sig->r);
1017     BN_bin2bn(jws->sig + key_len, key_len, ecdsa_sig->s);
1018 #endif
1019 
1020     if (ECDSA_do_verify(jws->dig, jws->dig_len, ecdsa_sig, ec) != 1)
1021     {
1022         CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1023         goto _cjose_jws_verify_sig_ec_cleanup;
1024     }
1025 
1026     // if we got this far - success
1027     retval = true;
1028 
1029 _cjose_jws_verify_sig_ec_cleanup:
1030     if (ecdsa_sig)
1031         ECDSA_SIG_free(ecdsa_sig);
1032 
1033     return retval;
1034 }
1035 
1036 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_verify(cjose_jws_t * jws,const cjose_jwk_t * jwk,cjose_err * err)1037 bool cjose_jws_verify(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
1038 {
1039     if (NULL == jws || NULL == jwk)
1040     {
1041         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1042         return false;
1043     }
1044 
1045     // validate JWS header
1046     if (!_cjose_jws_validate_hdr(jws, err))
1047     {
1048         return false;
1049     }
1050 
1051     // build JWS digest from header and payload (hashed signing input value)
1052     if (!jws->fns.digest(jws, jwk, err))
1053     {
1054         return false;
1055     }
1056 
1057     // verify JWS signature
1058     if (!jws->fns.verify(jws, jwk, err))
1059     {
1060         return false;
1061     }
1062 
1063     return true;
1064 }
1065 
1066 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_get_plaintext(const cjose_jws_t * jws,uint8_t ** plaintext,size_t * plaintext_len,cjose_err * err)1067 bool cjose_jws_get_plaintext(const cjose_jws_t *jws, uint8_t **plaintext, size_t *plaintext_len, cjose_err *err)
1068 {
1069     if (NULL == jws || NULL == plaintext || NULL == jws->dat)
1070     {
1071         CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1072         return false;
1073     }
1074 
1075     *plaintext = jws->dat;
1076     *plaintext_len = jws->dat_len;
1077 
1078     return true;
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
cjose_jws_get_protected(cjose_jws_t * jws)1082 cjose_header_t *cjose_jws_get_protected(cjose_jws_t *jws)
1083 {
1084     if (NULL == jws)
1085     {
1086         return NULL;
1087     }
1088 
1089     return (cjose_header_t *)jws->hdr;
1090 }
1091