bool _cjose_jwe_import_part( cjose_jwe_t *jwe, size_t p, const char *b64u, size_t b64u_len, cjose_err *err) { // only the ek and the data parts may be of zero length if (b64u_len == 0 && p != 1 && p != 3) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // copy the b64u part to the jwe jwe->part[p].b64u = strdup(b64u); if (NULL == jwe->part[p].b64u) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } jwe->part[p].b64u_len = b64u_len; // b64u decode the part if (!cjose_base64url_decode( jwe->part[p].b64u, jwe->part[p].b64u_len, (uint8_t **)&jwe->part[p].raw, &jwe->part[p].raw_len, err) || NULL == jwe->part[p].raw) { return false; } return true; }
/** * Internal helper function for extracing an octet string from a base64url * encoded field. Caller provides the json object, the attribute key, * and an expected length for the octet string. On successful decoding, * this will return a newly allocated buffer with the decoded octet string * of the expected length. * * Note: caller is responsible for freeing the buffer returned by this function. * * \param[in] json the JSON object from which to read the attribute. * \param[in] key the name of the attribute to be decoded. * \param[out] pointer to buffer of octet string (if decoding succeeds). * \param[in/out] in as the expected length of the attribute, out as the * actual decoded length. Note, this method succeeds only * if the actual decoded length matches the expected length. * If the in-value is 0 this indicates there is no particular * expected length (i.e. any length is ok). * \returns true if attribute is either not present or successfully decoded. * false otherwise. */ static bool _decode_json_object_base64url_attribute(json_t *jwk_json, const char *key, uint8_t **buffer, size_t *buflen, cjose_err *err) { // get the base64url encoded string value of the attribute (if any) const char *str = _get_json_object_string_attribute(jwk_json, key, err); if (str == NULL || strlen(str) == 0) { *buflen = 0; *buffer = NULL; return true; } // if a particular decoded length is expected, check for that if (*buflen != 0) { const char *end = NULL; for (end = str + strlen(str) - 1; *end == '=' && end > str; --end); size_t unpadded_len = end + 1 - str - ((*end == '=') ? 1 : 0); size_t expected_len = ceil(4 * ((float)*buflen / 3)); if (expected_len != unpadded_len) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); *buflen = 0; *buffer = NULL; return false; } } // decode the base64url encoded string to the allocated buffer if (!cjose_base64url_decode(str, strlen(str), buffer, buflen, err)) { *buflen = 0; *buffer = NULL; return false; } return true; }
cjose_jws_t *cjose_jws_import(const char *cser, size_t cser_len, cjose_err *err) { cjose_jws_t *jws = NULL; size_t len = 0; if (NULL == cser) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } // allocate and initialize a new JWS object jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t)); if (NULL == jws) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return NULL; } memset(jws, 0, sizeof(cjose_jws_t)); // find the indexes of the dots int idx = 0; int d[2] = { 0, 0 }; for (int i = 0; i < cser_len && idx < 2; ++i) { if (cser[i] == '.') { d[idx++] = i; } } // fail if we didn't find both dots if (0 == d[1]) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jws_release(jws); return NULL; } // copy and decode header b64u segment uint8_t *hdr_str = NULL; jws->hdr_b64u_len = d[0]; _cjose_jws_strcpy(&jws->hdr_b64u, cser, jws->hdr_b64u_len, err); if (!cjose_base64url_decode(jws->hdr_b64u, jws->hdr_b64u_len, &hdr_str, &len, err) || NULL == hdr_str) { cjose_jws_release(jws); return NULL; } // deserialize JSON header jws->hdr = json_loadb((const char *)hdr_str, len, 0, NULL); cjose_get_dealloc()(hdr_str); if (NULL == jws->hdr) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jws_release(jws); return NULL; } // validate the JSON header segment if (!_cjose_jws_validate_hdr(jws, err)) { // make an exception for alg=none so that it will import/parse but not sign/verify json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG); if (NULL == alg_obj) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } const char *alg = json_string_value(alg_obj); if ((!alg) || (strcmp(alg, CJOSE_HDR_ALG_NONE) != 0)) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jws_release(jws); return NULL; } } // copy and b64u decode data segment jws->dat_b64u_len = d[1] - d[0] - 1; _cjose_jws_strcpy(&jws->dat_b64u, cser + d[0] + 1, jws->dat_b64u_len, err); if (!cjose_base64url_decode(jws->dat_b64u, jws->dat_b64u_len, &jws->dat, &jws->dat_len, err)) { cjose_jws_release(jws); return NULL; } // copy and b64u decode signature segment jws->sig_b64u_len = cser_len - d[1] - 1; _cjose_jws_strcpy(&jws->sig_b64u, cser + d[1] + 1, jws->sig_b64u_len, err); if (!cjose_base64url_decode(jws->sig_b64u, jws->sig_b64u_len, &jws->sig, &jws->sig_len, err)) { cjose_jws_release(jws); return NULL; } return jws; }