Commit message: Fix buffer overflow on r_jwe_aesgcm_key_unwrap
CVE: None
CWE: CWE-787
Vulnerability description: None

Project: rhonabwy
File: jwe.c

int r_jwe_encrypt_payload(jwe_t * jwe) {
  int ret = RHN_OK, res;
  gnutls_cipher_hd_t handle;
  gnutls_datum_t key, iv;
  unsigned char * ptext = NULL, * text_zip = NULL, * ciphertext_b64url = NULL, tag[128] = {0}, * tag_b64url = NULL, * str_header_b64 = NULL, * aad = NULL;
  size_t ptext_len = 0, ciphertext_b64url_len = 0, tag_len = 0, tag_b64url_len = 0, str_header_b64_len = 0, text_zip_len = 0;
  char * str_header = NULL;
  int cipher_cbc;

  if (jwe != NULL &&
      jwe->payload != NULL &&
      jwe->payload_len &&
      jwe->enc != R_JWA_ENC_UNKNOWN &&
      jwe->key != NULL &&
      jwe->iv != NULL &&
      jwe->iv_len &&
      jwe->key_len == _r_get_key_size(jwe->enc) &&
      r_jwe_set_enc_header(jwe, jwe->j_header) == RHN_OK) {
    cipher_cbc = (jwe->enc == R_JWA_ENC_A128CBC || jwe->enc == R_JWA_ENC_A192CBC || jwe->enc == R_JWA_ENC_A256CBC);

    if ((str_header = json_dumps(jwe->j_header, JSON_COMPACT)) != NULL) {
      if ((str_header_b64 = o_malloc(o_strlen(str_header)*2)) != NULL) {
        if (o_base64url_encode((const unsigned char *)str_header, o_strlen(str_header), str_header_b64, &str_header_b64_len)) {
          o_free(jwe->header_b64url);
          jwe->header_b64url = (unsigned char *)o_strndup((const char *)str_header_b64, str_header_b64_len);
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error o_base64url_encode str_header");
          ret = RHN_ERROR;
        }
        o_free(str_header_b64);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error allocating resources for str_header_b64");
        ret = RHN_ERROR_MEMORY;
      }
      o_free(str_header);
    } else {
      y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error json_dumps j_header");
      ret = RHN_ERROR;
    }

    ptext_len = gnutls_cipher_get_block_size(_r_get_alg_from_enc(jwe->enc));
    if (0 == o_strcmp("DEF", r_jwe_get_header_str_value(jwe, "zip"))) {
      if (_r_deflate_payload(jwe->payload, jwe->payload_len, &text_zip, &text_zip_len) == RHN_OK) {
        if (r_jwe_set_ptext_with_block(text_zip, text_zip_len, &ptext, &ptext_len, _r_get_alg_from_enc(jwe->enc), cipher_cbc) != RHN_OK) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error r_jwe_set_ptext_with_block");
          ret = RHN_ERROR;
        }
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error _r_deflate_payload");
        ret = RHN_ERROR;
      }
      o_free(text_zip);
    } else {
      if (r_jwe_set_ptext_with_block(jwe->payload, jwe->payload_len, &ptext, &ptext_len, _r_get_alg_from_enc(jwe->enc), cipher_cbc) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error r_jwe_set_ptext_with_block");
        ret = RHN_ERROR;
      }
    }

    if (ret == RHN_OK) {
      if (cipher_cbc) {
        key.data = jwe->key+(jwe->key_len/2);
        key.size = jwe->key_len/2;
      } else {
        key.data = jwe->key;
        key.size = jwe->key_len;
      }
      iv.data = jwe->iv;
      iv.size = jwe->iv_len;
      if (!(res = gnutls_cipher_init(&handle, _r_get_alg_from_enc(jwe->enc), &key, &iv))) {
        if (jwe->aad_b64url == NULL || jwe->token_mode == R_JSON_MODE_COMPACT) {
          aad = (unsigned char *)o_strdup((const char *)jwe->header_b64url);
        } else {
          aad = (unsigned char *)msprintf("%s.%s", jwe->header_b64url, jwe->aad_b64url);
        }
        if (!cipher_cbc && (res = gnutls_cipher_add_auth(handle, aad, o_strlen((const char *)aad)))) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error gnutls_cipher_add_auth: '%s'", gnutls_strerror(res));
          ret = RHN_ERROR;
        }
        if (ret == RHN_OK) {
          if (!(res = gnutls_cipher_encrypt(handle, ptext, ptext_len))) {
            if ((ciphertext_b64url = o_malloc(2*ptext_len)) != NULL) {
              if (o_base64url_encode(ptext, ptext_len, ciphertext_b64url, &ciphertext_b64url_len)) {
                o_free(jwe->ciphertext_b64url);
                jwe->ciphertext_b64url = (unsigned char *)o_strndup((const char *)ciphertext_b64url, ciphertext_b64url_len);
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error o_base64url_encode ciphertext");
                ret = RHN_ERROR;
              }
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error allocating resources for ciphertext_b64url");
              ret = RHN_ERROR_MEMORY;
            }
            o_free(ciphertext_b64url);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error gnutls_cipher_encrypt: '%s'", gnutls_strerror(res));
            ret = RHN_ERROR;
          }
        } else if (!cipher_cbc) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error gnutls_cipher_add_auth: '%s'", gnutls_strerror(res));
          ret = RHN_ERROR;
        }
        if (ret == RHN_OK) {
          if (cipher_cbc) {
            if (r_jwe_compute_hmac_tag(jwe, ptext, ptext_len, aad, tag, &tag_len) != RHN_OK) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error r_jwe_compute_hmac_tag");
              ret = RHN_ERROR;
            }
          } else {
            tag_len = gnutls_cipher_get_tag_size(_r_get_alg_from_enc(jwe->enc));
            memset(tag, 0, tag_len);
            if ((res = gnutls_cipher_tag(handle, tag, tag_len))) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error gnutls_cipher_tag: '%s'", gnutls_strerror(res));
              ret = RHN_ERROR;
            }
          }
          if (ret == RHN_OK && tag_len) {
            if ((tag_b64url = o_malloc(tag_len*2)) != NULL) {
              if (o_base64url_encode(tag, tag_len, tag_b64url, &tag_b64url_len)) {
                o_free(jwe->auth_tag_b64url);
                jwe->auth_tag_b64url = (unsigned char *)o_strndup((const char *)tag_b64url, tag_b64url_len);
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error o_base64url_encode tag_b64url");
                ret = RHN_ERROR;
              }
              o_free(tag_b64url);
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error allocating resources for tag_b64url");
              ret = RHN_ERROR_MEMORY;
            }
          }
        }
        o_free(aad);
        gnutls_cipher_deinit(handle);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error gnutls_cipher_init: '%s'", gnutls_strerror(res));
        ret = RHN_ERROR;
      }
    }
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_encrypt_payload - Error input parameters");
    ret = RHN_ERROR_PARAM;
  }
  o_free(ptext);
  return ret;
}

Project: rhonabwy
File: jwe.c

static int r_jwe_aes_key_unwrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags) {
  int ret;
  uint8_t kek[32] = {0}, key_data[64], cipherkey[128] = {0};
  size_t kek_len = 0, cipherkey_len = 0;
  unsigned int bits = 0;

  if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC) {
    ret = RHN_OK;

    do {
      if (alg == R_JWA_ALG_A128KW && bits != 128) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error invalid key size, expected 128 bits");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (alg == R_JWA_ALG_A192KW && bits != 192) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error invalid key size, expected 192 bits");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (alg == R_JWA_ALG_A256KW && bits != 256) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error invalid key size, expected 256 bits");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, kek, &kek_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error r_jwk_export_to_symmetric_key");
        ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_decode(jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), NULL, &cipherkey_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error o_base64url_decode cipherkey");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (cipherkey_len > 72) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error invalid cipherkey len");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (!o_base64url_decode(jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), cipherkey, &cipherkey_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error o_base64url_decode cipherkey");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (!_r_aes_key_unwrap(kek, kek_len, key_data, cipherkey_len-8, cipherkey)) {
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (r_jwe_set_cypher_key(jwe, key_data, cipherkey_len-8) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error r_jwe_set_cypher_key");
        ret = RHN_ERROR;
      }
    } while (0);
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_unwrap - Error invalid key");
    ret = RHN_ERROR_INVALID;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

static json_t * r_jwe_aes_key_wrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags, int * ret) {
  uint8_t kek[32] = {0}, wrapped_key[72] = {0};
  unsigned char cipherkey_b64url[256] = {0};
  size_t kek_len = 0, cipherkey_b64url_len = 0;
  unsigned int bits = 0;
  json_t * j_return = NULL;

  if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC) {
    do {
      if (alg == R_JWA_ALG_A128KW && bits != 128) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error invalid key size, expected 128 bits");
        *ret = RHN_ERROR_PARAM;
        break;
      }
      if (alg == R_JWA_ALG_A192KW && bits != 192) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error invalid key size, expected 192 bits");
        *ret = RHN_ERROR_PARAM;
        break;
      }
      if (alg == R_JWA_ALG_A256KW && bits != 256) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error invalid key size, expected 256 bits");
        *ret = RHN_ERROR_PARAM;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, kek, &kek_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error r_jwk_export_to_symmetric_key");
        *ret = RHN_ERROR;
        break;
      }
      _r_aes_key_wrap(kek, kek_len, jwe->key, jwe->key_len, wrapped_key);
      if (!o_base64url_encode(wrapped_key, jwe->key_len+8, cipherkey_b64url, &cipherkey_b64url_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error o_base64url_encode wrapped_key");
        *ret = RHN_ERROR;
        break;
      }
      j_return = json_pack("{ss%s{ss}}", "encrypted_key", cipherkey_b64url, cipherkey_b64url_len, "header", "alg", r_jwa_alg_to_str(alg));
      o_free(jwe->encrypted_key_b64url);
      jwe->encrypted_key_b64url = (unsigned char *)o_strndup((const char *)cipherkey_b64url, cipherkey_b64url_len);
    } while (0);
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error invalid key");
    *ret = RHN_ERROR_PARAM;
  }
  return j_return;
}

Project: rhonabwy
File: jwe.c

int r_jwe_generate_iv(jwe_t * jwe) {
  int ret;
  unsigned char * iv_b64 = NULL;
  size_t iv_b64_len = 0;

  if (jwe != NULL && jwe->enc != R_JWA_ENC_UNKNOWN) {
    o_free(jwe->iv_b64url);
    jwe->iv_b64url = NULL;
    jwe->iv_len = gnutls_cipher_get_iv_size(_r_get_alg_from_enc(jwe->enc));
    o_free(jwe->iv);
    jwe->iv = NULL;
    if (jwe->iv_len) {
      if ((jwe->iv = o_malloc(jwe->iv_len)) != NULL) {
        if (!gnutls_rnd(GNUTLS_RND_NONCE, jwe->iv, jwe->iv_len)) {
          if ((iv_b64 = o_malloc(jwe->iv_len*2)) != NULL) {
            if (o_base64url_encode(jwe->iv, jwe->iv_len, iv_b64, &iv_b64_len)) {
              jwe->iv_b64url = (unsigned char *)o_strndup((const char *)iv_b64, iv_b64_len);
              ret = RHN_OK;
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_generate_iv - Error o_base64url_encode iv_b64");
              ret = RHN_ERROR;
            }
            o_free(iv_b64);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_generate_iv - Error allocating resources for iv_b64");
            ret = RHN_ERROR_MEMORY;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_generate_iv - Error gnutls_rnd");
          ret = RHN_ERROR;
        }
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_generate_iv - Error allocating resources for iv");
        ret = RHN_ERROR_MEMORY;
      }
    } else {
      jwe->iv_b64url = (unsigned char *)o_strdup("");
      ret = RHN_OK;
    }
  } else {
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

int r_jwe_decrypt_payload(jwe_t * jwe) {
  int ret = RHN_OK, res;
  gnutls_cipher_hd_t handle;
  gnutls_datum_t key, iv;
  unsigned char * payload_enc = NULL, * ciphertext = NULL, * unzip = NULL, * aad = NULL;
  size_t payload_enc_len = 0, ciphertext_len = 0, unzip_len = 0;
  unsigned char tag[128], * tag_b64url = NULL;
  size_t tag_len = 0, tag_b64url_len = 0;
  int cipher_cbc;

  if (jwe != NULL && jwe->enc != R_JWA_ENC_UNKNOWN && !o_strnullempty((const char *)jwe->ciphertext_b64url) && !o_strnullempty((const char *)jwe->iv_b64url) && jwe->key != NULL && jwe->key_len && jwe->key_len == _r_get_key_size(jwe->enc)) {
    // Decode iv and payload_b64
    o_free(jwe->iv);
    if ((jwe->iv = o_malloc(o_strlen((const char *)jwe->iv_b64url))) != NULL) {
      if (o_base64url_decode(jwe->iv_b64url, o_strlen((const char *)jwe->iv_b64url), jwe->iv, &jwe->iv_len)) {
        if ((jwe->iv = o_realloc(jwe->iv, jwe->iv_len)) != NULL) {
          if ((payload_enc = o_malloc(o_strlen((const char *)jwe->ciphertext_b64url))) != NULL && (ciphertext = o_malloc(o_strlen((const char *)jwe->ciphertext_b64url))) != NULL) {
            if (!o_base64url_decode(jwe->ciphertext_b64url, o_strlen((const char *)jwe->ciphertext_b64url), ciphertext, &ciphertext_len)) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error o_base64url_decode ciphertext");
              ret = RHN_ERROR;
            }
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error allocating resources for payload_enc or ciphertext");
            ret = RHN_ERROR_MEMORY;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error reallocating resources for iv");
          ret = RHN_ERROR_MEMORY;
        }
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error o_base64url_decode iv");
        ret = RHN_ERROR;
      }
    } else {
      y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error allocating resources for iv");
      ret = RHN_ERROR_MEMORY;
    }

    if (ret == RHN_OK) {
      if (jwe->enc == R_JWA_ENC_A128CBC || jwe->enc == R_JWA_ENC_A192CBC || jwe->enc == R_JWA_ENC_A256CBC) {
        key.data = jwe->key+(jwe->key_len/2);
        key.size = jwe->key_len/2;
        cipher_cbc = 1;
      } else {
        key.data = jwe->key;
        key.size = jwe->key_len;
        cipher_cbc = 0;
      }
      iv.data = jwe->iv;
      iv.size = jwe->iv_len;
      payload_enc_len = ciphertext_len;
      if (!(res = gnutls_cipher_init(&handle, _r_get_alg_from_enc(jwe->enc), &key, &iv))) {
        if (jwe->aad_b64url == NULL || jwe->token_mode == R_JSON_MODE_COMPACT) {
          aad = (unsigned char *)o_strdup((const char *)jwe->header_b64url);
        } else {
          aad = (unsigned char *)msprintf("%s.%s", jwe->header_b64url, jwe->aad_b64url);
        }
        if (!cipher_cbc && (res = gnutls_cipher_add_auth(handle, aad, o_strlen((const char *)aad)))) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error gnutls_cipher_add_auth: '%s'", gnutls_strerror(res));
          ret = RHN_ERROR;
        }
        if (!(res = gnutls_cipher_decrypt2(handle, ciphertext, ciphertext_len, payload_enc, payload_enc_len))) {
          if (cipher_cbc) {
            r_jwe_remove_padding(payload_enc, &payload_enc_len, gnutls_cipher_get_block_size(_r_get_alg_from_enc(jwe->enc)));
          }
          if (0 == o_strcmp("DEF", r_jwe_get_header_str_value(jwe, "zip"))) {
            if (_r_inflate_payload(payload_enc, payload_enc_len, &unzip, &unzip_len) == RHN_OK) {
              if (r_jwe_set_payload(jwe, unzip, unzip_len) != RHN_OK) {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error r_jwe_set_payload");
                ret = RHN_ERROR;
              }
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error _r_inflate_payload");
              ret = RHN_ERROR;
            }
            o_free(unzip);
          } else {
            if (r_jwe_set_payload(jwe, payload_enc, payload_enc_len) != RHN_OK) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error r_jwe_set_payload");
              ret = RHN_ERROR;
            }
          }
        } else if (res == GNUTLS_E_DECRYPTION_FAILED) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - decryption failed: '%s'", gnutls_strerror(res));
          ret = RHN_ERROR_INVALID;
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error gnutls_cipher_decrypt: '%s'", gnutls_strerror(res));
          ret = RHN_ERROR;
        }
        if (ret == RHN_OK) {
          if (cipher_cbc) {
            if (r_jwe_compute_hmac_tag(jwe, ciphertext, ciphertext_len, aad, tag, &tag_len) != RHN_OK) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error r_jwe_compute_hmac_tag");
              ret = RHN_ERROR;
            }
          } else {
            tag_len = gnutls_cipher_get_tag_size(_r_get_alg_from_enc(jwe->enc));
            memset(tag, 0, tag_len);
            if ((res = gnutls_cipher_tag(handle, tag, tag_len))) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error gnutls_cipher_tag: '%s'", gnutls_strerror(res));
              ret = RHN_ERROR;
            }
          }
          if (ret == RHN_OK && tag_len) {
            if ((tag_b64url = o_malloc(tag_len*2)) != NULL) {
              if (o_base64url_encode(tag, tag_len, tag_b64url, &tag_b64url_len)) {
                if (tag_b64url_len != o_strlen((const char *)jwe->auth_tag_b64url) || 0 != memcmp(tag_b64url, jwe->auth_tag_b64url, tag_b64url_len)) {
                  y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Invalid tag");
                  ret = RHN_ERROR_INVALID;
                }
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error o_base64url_encode tag_b64url");
                ret = RHN_ERROR;
              }
              o_free(tag_b64url);
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error allocating resources for tag_b64url");
              ret = RHN_ERROR_MEMORY;
            }
          }
        }
        o_free(aad);
        gnutls_cipher_deinit(handle);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error gnutls_cipher_init: '%s'", gnutls_strerror(res));
        ret = RHN_ERROR;
      }
    }
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_decrypt_payload - Error input parameters");
    ret = RHN_ERROR_PARAM;
  }
  o_free(payload_enc);
  o_free(ciphertext);

  return ret;
}

Project: rhonabwy
File: jwe.c

static json_t * r_jwe_perform_key_encryption(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags, int * ret) {
  json_t * j_return = NULL;
  int res;
  unsigned int bits = 0;
  gnutls_pubkey_t g_pub = NULL;
  gnutls_datum_t plainkey, cypherkey = {NULL, 0};
  unsigned char * cypherkey_b64 = NULL, key[128] = {0};
  size_t cypherkey_b64_len = 0, key_len = 0, index = 0;
  const char * key_ref = NULL;
  json_t * j_element = NULL, * j_reference, * j_key_ref_array;
#if NETTLE_VERSION_NUMBER >= 0x030400
  uint8_t * cyphertext = NULL;
  size_t cyphertext_len = 0;
#endif
#if NETTLE_VERSION_NUMBER >= 0x030600
  json_t * jwk_priv = NULL;
#endif

  switch (alg) {
    case R_JWA_ALG_RSA1_5:
      res = r_jwk_key_type(jwk, &bits, x5u_flags);
      if (res & (R_KEY_TYPE_RSA|R_KEY_TYPE_PUBLIC) && bits >= 2048) {
        if (jwk != NULL && (g_pub = r_jwk_export_to_gnutls_pubkey(jwk, x5u_flags)) != NULL) {
          plainkey.data = jwe->key;
          plainkey.size = jwe->key_len;
          if (!(res = gnutls_pubkey_encrypt_data(g_pub, 0, &plainkey, &cypherkey))) {
            if ((cypherkey_b64 = o_malloc(cypherkey.size*2)) != NULL) {
              if (o_base64url_encode(cypherkey.data, cypherkey.size, cypherkey_b64, &cypherkey_b64_len)) {
                j_return = json_pack("{ss%s{ss}}", "encrypted_key", cypherkey_b64, cypherkey_b64_len, "header", "alg", r_jwa_alg_to_str(alg));
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error o_base64url_encode cypherkey_b64");
                *ret = RHN_ERROR;
              }
              o_free(cypherkey_b64);
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error o_malloc cypherkey_b64");
              *ret = RHN_ERROR_MEMORY;
            }
            gnutls_free(cypherkey.data);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error gnutls_pubkey_encrypt_data: %s", gnutls_strerror(res));
            *ret = RHN_ERROR;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Unable to export public key");
          *ret = RHN_ERROR;
        }
        gnutls_pubkey_deinit(g_pub);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error invalid key type");
        *ret = RHN_ERROR_PARAM;
      }
      break;
#if NETTLE_VERSION_NUMBER >= 0x030400
    case R_JWA_ALG_RSA_OAEP:
    case R_JWA_ALG_RSA_OAEP_256:
      res = r_jwk_key_type(jwk, &bits, x5u_flags);
      if (res & (R_KEY_TYPE_RSA|R_KEY_TYPE_PUBLIC) && bits >= 2048) {
        if (jwk != NULL && (g_pub = r_jwk_export_to_gnutls_pubkey(jwk, x5u_flags)) != NULL) {
          if ((cyphertext = o_malloc(bits+1)) != NULL) {
            cyphertext_len = bits+1;
            if (_r_rsa_oaep_encrypt(g_pub, alg, jwe->key, jwe->key_len, cyphertext, &cyphertext_len) == RHN_OK) {
              if ((cypherkey_b64 = o_malloc(cyphertext_len*2)) != NULL) {
                if (o_base64url_encode(cyphertext, cyphertext_len, cypherkey_b64, &cypherkey_b64_len)) {
                  j_return = json_pack("{ss%s{ss}}", "encrypted_key", cypherkey_b64, cypherkey_b64_len, "header", "alg", r_jwa_alg_to_str(alg));
                } else {
                  y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error o_base64url_encode cypherkey_b64");
                  *ret = RHN_ERROR;
                }
                o_free(cypherkey_b64);
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error o_malloc cypherkey_b64");
                *ret = RHN_ERROR_MEMORY;
              }
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error _r_rsa_oaep_encrypt");
              *ret = RHN_ERROR;
            }
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error allocating resources for cyphertext");
            *ret = RHN_ERROR_MEMORY;
          }
          o_free(cyphertext);
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Unable to export public key");
          *ret = RHN_ERROR;
        }
        gnutls_pubkey_deinit(g_pub);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error invalid key type");
        *ret = RHN_ERROR_PARAM;
      }
      break;
#endif
    case R_JWA_ALG_DIR:
      o_free(jwe->encrypted_key_b64url);
      jwe->encrypted_key_b64url = NULL;
      if (jwk != NULL) {
        if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC && bits == _r_get_key_size(jwe->enc)*8) {
          key_len = bits/8;
          if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) != RHN_OK) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error r_jwk_export_to_symmetric_key");
            *ret = RHN_ERROR;
          } else {
            if (r_jwe_set_cypher_key(jwe, key, key_len) != RHN_OK) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error r_jwe_set_cypher_key");
              *ret = RHN_ERROR;
            } else {
              j_return = json_object();
            }
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error invalid key type");
          *ret = RHN_ERROR_PARAM;
        }
      } else if (jwe->key != NULL && jwe->key_len > 0) {
        j_return = json_object();
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error no key available for alg 'dir'");
        *ret = RHN_ERROR_PARAM;
      }
      break;
    case R_JWA_ALG_A128GCMKW:
#if GNUTLS_VERSION_NUMBER >= 0x03060e
    case R_JWA_ALG_A192GCMKW:
#endif
    case R_JWA_ALG_A256GCMKW:
      if ((j_return = r_jwe_aesgcm_key_wrap(jwe, alg, jwk, x5u_flags, ret)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error r_jwe_aesgcm_key_wrap");
      }
      break;
#if NETTLE_VERSION_NUMBER >= 0x030400
    case R_JWA_ALG_A128KW:
    case R_JWA_ALG_A192KW:
    case R_JWA_ALG_A256KW:
      if ((j_return = r_jwe_aes_key_wrap(jwe, alg, jwk, x5u_flags, ret)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error r_jwe_aes_key_wrap");
      }
      break;
#endif
#if GNUTLS_VERSION_NUMBER >= 0x03060d
    case R_JWA_ALG_PBES2_H256:
    case R_JWA_ALG_PBES2_H384:
    case R_JWA_ALG_PBES2_H512:
      if ((j_return = r_jwe_pbes2_key_wrap(jwe, alg, jwk, x5u_flags, ret)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error r_jwe_pbes2_key_wrap");
      }
      break;
#endif
#if NETTLE_VERSION_NUMBER >= 0x030600
    case R_JWA_ALG_ECDH_ES:
    case R_JWA_ALG_ECDH_ES_A128KW:
    case R_JWA_ALG_ECDH_ES_A192KW:
    case R_JWA_ALG_ECDH_ES_A256KW:
      res = r_jwk_key_type(jwk, &bits, x5u_flags);
      if (res & (R_KEY_TYPE_EC|R_KEY_TYPE_PUBLIC)) {
        if (r_jwks_size(jwe->jwks_privkey) == 1) {
          jwk_priv = r_jwks_get_at(jwe->jwks_privkey, 0);
        }
        if ((j_return = _r_jwe_ecdh_encrypt(jwe, alg, jwk, jwk_priv, res, bits, x5u_flags, ret)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Error _r_jwe_ecdh_encrypt");
        }
        r_jwk_free(jwk_priv);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - invalid public key type");
        *ret = RHN_ERROR_PARAM;
      }
      break;
#endif
    default:
      y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_perform_key_encryption - Unsupported alg");
      *ret = RHN_ERROR_PARAM;
      break;
  }
  j_key_ref_array = json_array();
  json_object_foreach(json_object_get(j_return, "header"), key_ref, j_element) {
    j_reference = json_object_get(jwe->j_header, key_ref);
    if (j_reference == NULL) {
      j_reference = json_object_get(jwe->j_unprotected_header, key_ref);
    }
    if (j_reference != NULL && json_equal(j_reference, j_element)) {
      json_array_append_new(j_key_ref_array, json_string(key_ref));
    }
  }
  json_array_foreach(j_key_ref_array, index, j_element) {
    json_object_del(json_object_get(j_return, "header"), json_string_value(j_element));
  }
  json_decref(j_key_ref_array);
  if (!json_object_size(json_object_get(j_return, "header"))) {
    json_object_del(j_return, "header");
  }
  return j_return;
}

Project: rhonabwy
File: jwe.c

static int r_jwe_aesgcm_key_unwrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags) {
  int ret, res;
  unsigned char iv[96] = {0}, * key = NULL, cipherkey[64] = {0}, tag[128] = {0}, tag_b64url[256] = {0};
  size_t iv_len = 0, key_len = 0, cipherkey_len = 0, tag_b64url_len = 0, tag_len = gnutls_cipher_get_tag_size(r_jwe_get_alg_from_alg(alg));
  unsigned int bits = 0;
  gnutls_datum_t key_g, iv_g;
  gnutls_cipher_hd_t handle = NULL;

  if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC && o_strlen(r_jwe_get_header_str_value(jwe, "iv")) && o_strlen(r_jwe_get_header_str_value(jwe, "tag"))) {
    ret = RHN_OK;
    key_len = bits;

    do {
      if ((key = o_malloc(key_len+4)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error allocating resources for key");
        ret = RHN_ERROR_MEMORY;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error r_jwk_export_to_symmetric_key");
        ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_decode((const unsigned char *)r_jwe_get_header_str_value(jwe, "iv"), o_strlen(r_jwe_get_header_str_value(jwe, "iv")), NULL, &iv_len) || iv_len > 96) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Invalid header iv");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (!o_base64url_decode((const unsigned char *)r_jwe_get_header_str_value(jwe, "iv"), o_strlen(r_jwe_get_header_str_value(jwe, "iv")), iv, &iv_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error o_base64url_decode iv");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (!o_base64url_decode((const unsigned char *)jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), NULL, &cipherkey_len) || cipherkey_len > 64) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Invalid cipherkey");
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (!o_base64url_decode((const unsigned char *)jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), cipherkey, &cipherkey_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error o_base64url_decode cipherkey");
        ret = RHN_ERROR_INVALID;
        break;
      }
      key_g.data = key;
      key_g.size = key_len;
      iv_g.data = iv;
      iv_g.size = iv_len;
      if ((res = gnutls_cipher_init(&handle, r_jwe_get_alg_from_alg(alg), &key_g, &iv_g))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error gnutls_cipher_init: '%s'", gnutls_strerror(res));
        ret = RHN_ERROR_INVALID;
        break;
      }
      if ((res = gnutls_cipher_decrypt(handle, cipherkey, cipherkey_len))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error gnutls_cipher_decrypt: '%s'", gnutls_strerror(res));
        ret = RHN_ERROR;
        break;
      }
      if ((res = gnutls_cipher_tag(handle, tag, tag_len))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error gnutls_cipher_tag: '%s'", gnutls_strerror(res));
        ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_encode(tag, tag_len, tag_b64url, &tag_b64url_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error o_base64url_encode tag");
        ret = RHN_ERROR;
        break;
      }
      tag_b64url[tag_b64url_len] = '\0';
      if (0 != o_strcmp((const char *)tag_b64url, r_jwe_get_header_str_value(jwe, "tag"))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Invalid tag %s %s", tag_b64url, r_jwe_get_header_str_value(jwe, "tag"));
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (r_jwe_set_cypher_key(jwe, cipherkey, cipherkey_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error r_jwe_set_cypher_key");
        ret = RHN_ERROR;
      }

    } while (0);
    o_free(key);
    if (handle != NULL) {
      gnutls_cipher_deinit(handle);
    }
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_unwrap - Error invalid key");
    ret = RHN_ERROR_INVALID;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

int r_jwe_set_iv(jwe_t * jwe, const unsigned char * iv, size_t iv_len) {
  int ret;
  unsigned char * iv_b64 = NULL;
  size_t iv_b64_len = 0;

  if (jwe != NULL) {
    o_free(jwe->iv);
    if (iv != NULL && iv_len) {
      if ((jwe->iv = o_malloc(iv_len)) != NULL) {
        memcpy(jwe->iv, iv, iv_len);
        jwe->iv_len = iv_len;
        if ((iv_b64 = o_malloc(jwe->iv_len*2)) != NULL) {
          if (o_base64url_encode(jwe->iv, jwe->iv_len, iv_b64, &iv_b64_len)) {
            o_free(jwe->iv_b64url);
            jwe->iv_b64url = (unsigned char *)o_strndup((const char *)iv_b64, iv_b64_len);
            ret = RHN_OK;
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_iv - Error o_base64url_encode iv_b64");
            ret = RHN_ERROR;
          }
          o_free(iv_b64);
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_iv - Error allocating resources for iv_b64");
          ret = RHN_ERROR_MEMORY;
        }
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_iv - Error allocating resources for iv");
        ret = RHN_ERROR_MEMORY;
      }
    } else {
      jwe->iv = NULL;
      jwe->iv_len = 0;
      ret = RHN_OK;
    }
  } else {
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

static int r_jwe_pbes2_key_unwrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags) {
  unsigned char * salt = NULL, kek[64] = {0}, * key = NULL, cipherkey[128] = {0}, key_data[64] = {0}, * p2s_dec = NULL;
  size_t alg_len, salt_len, key_len = 0, cipherkey_len = 0, p2s_dec_len = 0, kek_len = 0;
  int ret;
  const char * p2s;
  unsigned int p2c;
  gnutls_datum_t password = {NULL, 0}, g_salt = {NULL, 0};
  gnutls_mac_algorithm_t mac = GNUTLS_MAC_UNKNOWN;

  if (r_jwk_key_type(jwk, NULL, x5u_flags) & R_KEY_TYPE_SYMMETRIC) {
    ret = RHN_OK;

    do {
      alg_len = o_strlen(r_jwe_get_header_str_value(jwe, "alg"));
      if ((p2c = (unsigned int)r_jwe_get_header_int_value(jwe, "p2c")) <= 0) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error invalid p2c");
        ret = RHN_ERROR_PARAM;
        break;
      }
      if (o_strlen(r_jwe_get_header_str_value(jwe, "p2s")) < 8) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error invalid p2s");
        ret = RHN_ERROR_PARAM;
        break;
      }
      p2s = r_jwe_get_header_str_value(jwe, "p2s");
      if ((p2s_dec = o_malloc(o_strlen(p2s))) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error o_malloc p2s_dec");
        ret = RHN_ERROR_MEMORY;
        break;
      }
      if (!o_base64url_decode((const unsigned char *)p2s, o_strlen(p2s), p2s_dec, &p2s_dec_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error o_base64url_decode p2s_dec");
        ret = RHN_ERROR;
        break;
      }
      salt_len = p2s_dec_len + alg_len + 1;
      if ((salt = o_malloc(salt_len)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error o_malloc salt");
        ret = RHN_ERROR_MEMORY;
        break;
      }
      memcpy(salt, r_jwe_get_header_str_value(jwe, "alg"), alg_len);
      memset(salt+alg_len, 0, 1);
      memcpy(salt+alg_len+1, p2s_dec, p2s_dec_len);

      if (r_jwk_export_to_symmetric_key(jwk, NULL, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error r_jwk_export_to_symmetric_key (1)");
        ret = RHN_ERROR;
        break;
      }
      key_len += 4;
      if ((key = o_malloc(key_len)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error o_malloc key");
        ret = RHN_ERROR_MEMORY;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error r_jwk_export_to_symmetric_key (2)");
        ret = RHN_ERROR;
        break;
      }
      password.data = key;
      password.size = key_len;
      g_salt.data = salt;
      g_salt.size = salt_len;
      if (alg == R_JWA_ALG_PBES2_H256) {
        kek_len = 16;
        mac = GNUTLS_MAC_SHA256;
      } else if (alg == R_JWA_ALG_PBES2_H384) {
        kek_len = 24;
        mac = GNUTLS_MAC_SHA384;
      } else if (alg == R_JWA_ALG_PBES2_H512) {
        kek_len = 32;
        mac = GNUTLS_MAC_SHA512;
      }
      if (gnutls_pbkdf2(mac, &password, &g_salt, p2c, kek, kek_len) != GNUTLS_E_SUCCESS) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error gnutls_pbkdf2");
        ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_decode(jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), cipherkey, &cipherkey_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error o_base64url_decode cipherkey");
        ret = RHN_ERROR;
        break;
      }
      if (!_r_aes_key_unwrap(kek, kek_len, key_data, cipherkey_len-8, cipherkey)) {
        ret = RHN_ERROR_INVALID;
        break;
      }
      if (r_jwe_set_cypher_key(jwe, key_data, cipherkey_len-8) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error r_jwe_set_cypher_key");
        ret = RHN_ERROR;
      }
    } while (0);
    o_free(key);
    o_free(salt);
    o_free(p2s_dec);
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error invalid key");
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

static json_t * r_jwe_aesgcm_key_wrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags, int * ret) {
  int res;
  unsigned char iv[96] = {0}, iv_b64url[192] = {0}, * key = NULL, cipherkey[64] = {0}, cipherkey_b64url[128] = {0}, tag[128] = {0}, tag_b64url[256] = {0};
  size_t iv_b64url_len = 0, key_len = 0, cipherkey_b64url_len = 0, tag_b64url_len = 0, iv_size = gnutls_cipher_get_iv_size(r_jwe_get_alg_from_alg(alg)), tag_len = gnutls_cipher_get_tag_size(r_jwe_get_alg_from_alg(alg));
  unsigned int bits = 0;
  gnutls_datum_t key_g, iv_g;
  gnutls_cipher_hd_t handle = NULL;
  json_t * j_return = NULL;

  if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC) {
    key_len = bits;

    do {
      if ((key = o_malloc(key_len+4)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error allocating resources for key");
        *ret = RHN_ERROR_MEMORY;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error r_jwk_export_to_symmetric_key");
        *ret = RHN_ERROR_PARAM;
        break;
      }
      if (r_jwe_get_header_str_value(jwe, "iv") == NULL) {
        if (gnutls_rnd(GNUTLS_RND_NONCE, iv, iv_size)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error gnutls_rnd");
          *ret = RHN_ERROR;
          break;
        }
        if (!o_base64url_encode(iv, iv_size, iv_b64url, &iv_b64url_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error o_base64url_encode iv");
          *ret = RHN_ERROR;
          break;
        }
        iv_b64url[iv_b64url_len] = '\0';
      } else {
        if (!o_base64url_decode((const unsigned char *)r_jwe_get_header_str_value(jwe, "iv"), o_strlen(r_jwe_get_header_str_value(jwe, "iv")), iv, &iv_size)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error o_base64url_decode iv");
          *ret = RHN_ERROR_PARAM;
          break;
        }
        if (iv_size != gnutls_cipher_get_iv_size(r_jwe_get_alg_from_alg(alg))) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error invalid iv size");
          *ret = RHN_ERROR_PARAM;
          break;
        }
      }
      key_g.data = key;
      key_g.size = key_len;
      iv_g.data = iv;
      iv_g.size = iv_size;
      if ((res = gnutls_cipher_init(&handle, r_jwe_get_alg_from_alg(alg), &key_g, &iv_g))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error gnutls_cipher_init: '%s'", gnutls_strerror(res));
        *ret = RHN_ERROR_PARAM;
        break;
      }
      if ((res = gnutls_cipher_encrypt2(handle, jwe->key, jwe->key_len, cipherkey, jwe->key_len))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error gnutls_cipher_encrypt2: '%s'", gnutls_strerror(res));
        *ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_encode(cipherkey, jwe->key_len, cipherkey_b64url, &cipherkey_b64url_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error o_base64url_encode cipherkey");
        *ret = RHN_ERROR;
        break;
      }
      if ((res = gnutls_cipher_tag(handle, tag, tag_len))) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error gnutls_cipher_tag: '%s'", gnutls_strerror(res));
        *ret = RHN_ERROR;
        break;
      }
      if (!o_base64url_encode(tag, tag_len, tag_b64url, &tag_b64url_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error o_base64url_encode tag");
        *ret = RHN_ERROR;
        break;
      }
      tag_b64url[tag_b64url_len] = '\0';
      j_return = json_pack("{ss%s{ssssss}}", "encrypted_key", cipherkey_b64url, cipherkey_b64url_len,
                                             "header",
                                               "iv", r_jwe_get_header_str_value(jwe, "iv")==NULL?(const char *)iv_b64url:r_jwe_get_header_str_value(jwe, "iv"),
                                               "tag", tag_b64url,
                                               "alg", r_jwa_alg_to_str(alg));
    } while (0);
    o_free(key);
    if (handle != NULL) {
      gnutls_cipher_deinit(handle);
    }
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aesgcm_key_wrap - Error invalid key");
    *ret = RHN_ERROR_PARAM;
  }
  return j_return;
}

Project: rhonabwy
File: jwe.c

static json_t * r_jwe_pbes2_key_wrap(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags, int * ret) {
  unsigned char salt_seed[_R_PBES_DEFAULT_SALT_LENGTH] = {0}, salt_seed_b64[_R_PBES_DEFAULT_SALT_LENGTH*2], * salt = NULL, kek[64] = {0}, * key = NULL, wrapped_key[72] = {0}, cipherkey_b64url[256] = {0}, * p2s_dec = NULL;
  size_t alg_len, salt_len, key_len = 0, cipherkey_b64url_len = 0, salt_seed_b64_len = 0, p2s_dec_len = 0, kek_len = 0;
  const char * p2s = NULL;
  unsigned int p2c = 0;
  gnutls_datum_t password = {NULL, 0}, g_salt = {NULL, 0};
  gnutls_mac_algorithm_t mac = GNUTLS_MAC_UNKNOWN;
  json_t * j_return = NULL;

  if (r_jwk_key_type(jwk, NULL, x5u_flags) & R_KEY_TYPE_SYMMETRIC) {
    do {
      alg_len = o_strlen(r_jwa_alg_to_str(alg));
      if ((p2s = r_jwe_get_header_str_value(jwe, "p2s")) != NULL) {
        if ((p2s_dec = o_malloc(o_strlen(p2s)*2)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_malloc p2s_dec");
          *ret = RHN_ERROR_MEMORY;
          break;
        }
        if (!o_base64url_decode((const unsigned char *)p2s, o_strlen(p2s), p2s_dec, &p2s_dec_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_base64url_decode p2s");
          *ret = RHN_ERROR_PARAM;
          break;
        }
        if (p2s_dec_len < 8) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error invalid p2s length");
          *ret = RHN_ERROR_PARAM;
          break;
        }
        salt_len = p2s_dec_len + alg_len + 1;
        if ((salt = o_malloc(salt_len)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_malloc salt (1)");
          *ret = RHN_ERROR_MEMORY;
          break;
        }
        memcpy(salt, r_jwa_alg_to_str(alg), alg_len);
        memset(salt+alg_len, 0, 1);
        memcpy(salt+alg_len+1, p2s_dec, p2s_dec_len);
      } else {
        if (gnutls_rnd(GNUTLS_RND_NONCE, salt_seed, _R_PBES_DEFAULT_SALT_LENGTH)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error gnutls_rnd");
          *ret = RHN_ERROR;
          break;
        }
        salt_len = _R_PBES_DEFAULT_SALT_LENGTH + alg_len + 1;
        if ((salt = o_malloc(salt_len)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_malloc salt (2)");
          *ret = RHN_ERROR_MEMORY;
          break;
        }
        if (!o_base64url_encode(salt_seed, _R_PBES_DEFAULT_SALT_LENGTH, salt_seed_b64, &salt_seed_b64_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_base64url_encode salt_seed");
          *ret = RHN_ERROR;
          break;
        }
        salt_seed_b64[salt_seed_b64_len] = '\0';

        memcpy(salt, r_jwa_alg_to_str(alg), alg_len);
        memset(salt+alg_len, 0, 1);
        memcpy(salt+alg_len+1, salt_seed, _R_PBES_DEFAULT_SALT_LENGTH);
      }
      if ((p2c = (unsigned int)r_jwe_get_header_int_value(jwe, "p2c")) <= 0) {
        p2c = _R_PBES_DEFAULT_ITERATION;
      }

      if (r_jwk_export_to_symmetric_key(jwk, NULL, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error r_jwk_export_to_symmetric_key (1)");
        *ret = RHN_ERROR;
        break;
      }
      key_len += 4;
      if ((key = o_malloc(key_len)) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error o_malloc key");
        *ret = RHN_ERROR_MEMORY;
        break;
      }
      if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) != RHN_OK) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error r_jwk_export_to_symmetric_key (2)");
        *ret = RHN_ERROR;
        break;
      }
      password.data = key;
      password.size = key_len;
      g_salt.data = salt;
      g_salt.size = salt_len;
      if (alg == R_JWA_ALG_PBES2_H256) {
        kek_len = 16;
        mac = GNUTLS_MAC_SHA256;
      } else if (alg == R_JWA_ALG_PBES2_H384) {
        kek_len = 24;
        mac = GNUTLS_MAC_SHA384;
      } else if (alg == R_JWA_ALG_PBES2_H512) {
        kek_len = 32;
        mac = GNUTLS_MAC_SHA512;
      }
      if (gnutls_pbkdf2(mac, &password, &g_salt, p2c, kek, kek_len) != GNUTLS_E_SUCCESS) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_unwrap - Error gnutls_pbkdf2");
        *ret = RHN_ERROR;
        break;
      }
      _r_aes_key_wrap(kek, kek_len, jwe->key, jwe->key_len, wrapped_key);
      if (!o_base64url_encode(wrapped_key, jwe->key_len+8, cipherkey_b64url, &cipherkey_b64url_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_aes_key_wrap - Error o_base64url_encode wrapped_key");
        *ret = RHN_ERROR;
        break;
      }
      j_return = json_pack("{ss%s{sssssi}}", "encrypted_key", cipherkey_b64url, cipherkey_b64url_len,
                                             "header",
                                               "alg", r_jwa_alg_to_str(alg),
                                               "p2s", p2s!=NULL?p2s:(const char*)salt_seed_b64,
                                               "p2c", p2c);
    } while (0);
    o_free(key);
    o_free(salt);
    o_free(p2s_dec);
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_pbes2_key_wrap - Error invalid key");
  }
  return j_return;
}

Project: rhonabwy
File: jwe.c

static int r_preform_key_decryption(jwe_t * jwe, jwa_alg alg, jwk_t * jwk, int x5u_flags) {
  int ret, res;
  gnutls_datum_t plainkey = {NULL, 0}, cypherkey;
  gnutls_privkey_t g_priv = NULL;
  unsigned int bits = 0;
  unsigned char * cypherkey_dec = NULL, * key = NULL;
  size_t cypherkey_dec_len = 0, key_len = 0;
#if NETTLE_VERSION_NUMBER >= 0x030400
  uint8_t * clearkey = NULL;
  size_t clearkey_len = 0;
#endif

  switch (alg) {
    case R_JWA_ALG_RSA1_5:
      if (r_jwk_key_type(jwk, &bits, x5u_flags) & (R_KEY_TYPE_RSA|R_KEY_TYPE_PRIVATE) && bits >= 2048) {
        if (jwk != NULL && !o_strnullempty((const char *)jwe->encrypted_key_b64url) && (g_priv = r_jwk_export_to_gnutls_privkey(jwk)) != NULL) {
          if ((cypherkey_dec = o_malloc(o_strlen((const char *)jwe->encrypted_key_b64url))) != NULL) {
            memset(cypherkey_dec, 0, o_strlen((const char *)jwe->encrypted_key_b64url));
            if (o_base64url_decode(jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), cypherkey_dec, &cypherkey_dec_len)) {
              cypherkey.size = cypherkey_dec_len;
              cypherkey.data = cypherkey_dec;
              if (!(res = gnutls_privkey_decrypt_data(g_priv, 0, &cypherkey, &plainkey))) {
                if (r_jwe_set_cypher_key(jwe, plainkey.data, plainkey.size) == RHN_OK) {
                  ret = RHN_OK;
                } else {
                  y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwe_set_cypher_key (RSA1_5)");
                  ret = RHN_ERROR;
                }
                gnutls_free(plainkey.data);
              } else if (res == GNUTLS_E_DECRYPTION_FAILED) {
                ret = RHN_ERROR_INVALID;
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error gnutls_privkey_decrypt_data: %s", gnutls_strerror(res));
                ret = RHN_ERROR;
              }
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error o_base64url_decode cypherkey_dec");
              ret = RHN_ERROR_PARAM;
            }
            o_free(cypherkey_dec);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error o_malloc cypherkey_dec");
            ret = RHN_ERROR_MEMORY;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid RSA1_5 input parameters");
          ret = RHN_ERROR_PARAM;
        }
        gnutls_privkey_deinit(g_priv);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid key size RSA1_5");
        ret = RHN_ERROR_INVALID;
      }
      break;
#if NETTLE_VERSION_NUMBER >= 0x030400
    case R_JWA_ALG_RSA_OAEP:
    case R_JWA_ALG_RSA_OAEP_256:
      if (r_jwk_key_type(jwk, &bits, x5u_flags) & (R_KEY_TYPE_RSA|R_KEY_TYPE_PRIVATE) && bits >= 2048) {
        if (jwk != NULL && !o_strnullempty((const char *)jwe->encrypted_key_b64url) && (g_priv = r_jwk_export_to_gnutls_privkey(jwk)) != NULL) {
          if ((cypherkey_dec = o_malloc(o_strlen((const char *)jwe->encrypted_key_b64url))) != NULL) {
            if (o_base64url_decode(jwe->encrypted_key_b64url, o_strlen((const char *)jwe->encrypted_key_b64url), cypherkey_dec, &cypherkey_dec_len)) {
              if ((clearkey = o_malloc(bits+1)) != NULL) {
                clearkey_len = bits+1;
                if (_r_rsa_oaep_decrypt(g_priv, alg, cypherkey_dec, cypherkey_dec_len, clearkey, &clearkey_len) == RHN_OK) {
                  if (_r_get_key_size(jwe->enc) == clearkey_len) {
                    if (r_jwe_set_cypher_key(jwe, clearkey, clearkey_len) == RHN_OK) {
                      ret = RHN_OK;
                    } else {
                      y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwe_set_cypher_key (RSA_OAEP)");
                      ret = RHN_ERROR;
                    }
                  } else {
                    y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid key length");
                    ret = RHN_ERROR_PARAM;
                  }
                } else {
                  y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error _r_rsa_oaep_decrypt");
                  ret = RHN_ERROR_INVALID;
                }
              } else {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error o_malloc clearkey");
                ret = RHN_ERROR_MEMORY;
              }
              o_free(clearkey);
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error o_base64url_decode cypherkey_dec");
              ret = RHN_ERROR_PARAM;
            }
            o_free(cypherkey_dec);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error o_malloc cypherkey_dec");
            ret = RHN_ERROR_MEMORY;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid RSA1-OAEP input parameters");
          ret = RHN_ERROR_PARAM;
        }
        gnutls_privkey_deinit(g_priv);
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid key size RSA_OAEP");
        ret = RHN_ERROR_INVALID;
      }
      break;
#endif
    case R_JWA_ALG_DIR:
      o_free(jwe->encrypted_key_b64url);
      jwe->encrypted_key_b64url = NULL;
      if (jwk != NULL) {
        if (r_jwk_key_type(jwk, &bits, x5u_flags) & R_KEY_TYPE_SYMMETRIC && bits == _r_get_key_size(jwe->enc)*8) {
          key_len = (size_t)(bits/8);
          if ((key = o_malloc(key_len+4)) != NULL) {
            if (r_jwk_export_to_symmetric_key(jwk, key, &key_len) == RHN_OK) {
              o_free(jwe->encrypted_key_b64url);
              jwe->encrypted_key_b64url = NULL;
              ret = r_jwe_set_cypher_key(jwe, key, key_len);
            } else {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwk_export_to_symmetric_key");
              ret = RHN_ERROR_MEMORY;
            }
            o_free(key);
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error allocating resources for key");
            ret = RHN_ERROR_MEMORY;
          }
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error invalid key type");
          ret = RHN_ERROR_PARAM;
        }
      } else if (jwe->key != NULL && jwe->key_len > 0) {
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error no key available for alg 'dir'");
        ret = RHN_ERROR_INVALID;
      }
      break;
    case R_JWA_ALG_A128GCMKW:
#if GNUTLS_VERSION_NUMBER >= 0x03060e
    case R_JWA_ALG_A192GCMKW:
#endif
    case R_JWA_ALG_A256GCMKW:
      if ((res = r_jwe_aesgcm_key_unwrap(jwe, alg, jwk, x5u_flags)) == RHN_OK) {
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwe_aesgcm_key_unwrap");
        ret = res;
      }
      break;
#if NETTLE_VERSION_NUMBER >= 0x030400
    case R_JWA_ALG_A128KW:
    case R_JWA_ALG_A192KW:
    case R_JWA_ALG_A256KW:
      if ((res = r_jwe_aes_key_unwrap(jwe, alg, jwk, x5u_flags)) == RHN_OK) {
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwe_aes_key_unwrap");
        ret = res;
      }
      break;
#endif
#if GNUTLS_VERSION_NUMBER >= 0x03060d
    case R_JWA_ALG_PBES2_H256:
    case R_JWA_ALG_PBES2_H384:
    case R_JWA_ALG_PBES2_H512:
      if ((res = r_jwe_pbes2_key_unwrap(jwe, alg, jwk, x5u_flags)) == RHN_OK) {
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error r_jwe_pbes2_key_unwrap");
        ret = res;
      }
      break;
#endif
#if NETTLE_VERSION_NUMBER >= 0x030600
    case R_JWA_ALG_ECDH_ES:
    case R_JWA_ALG_ECDH_ES_A128KW:
    case R_JWA_ALG_ECDH_ES_A192KW:
    case R_JWA_ALG_ECDH_ES_A256KW:
      res = r_jwk_key_type(jwk, &bits, x5u_flags);
      if (res & (R_KEY_TYPE_EC|R_KEY_TYPE_PRIVATE) || res & (R_KEY_TYPE_EDDSA|R_KEY_TYPE_PRIVATE)) {
        if ((res = _r_jwe_ecdh_decrypt(jwe, alg, jwk, res, bits, x5u_flags)) == RHN_OK) {
          ret = RHN_OK;
        } else {
          if (res != RHN_ERROR_INVALID) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error _r_jwe_ecdh_decrypt");
          }
          ret = res;
        }
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - invalid key type %d", res);
        ret = RHN_ERROR_INVALID;
      }
      break;
#endif
    default:
      y_log_message(Y_LOG_LEVEL_ERROR, "r_preform_key_decryption - Error unsupported algorithm");
      ret = RHN_ERROR_INVALID;
      break;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

int r_jwe_advanced_compact_parsen(jwe_t * jwe, const char * jwe_str, size_t jwe_str_len, uint32_t parse_flags, int x5u_flags) {
  int ret;
  char ** str_array = NULL;
  char * str_header = NULL, * token = NULL, * tmp;
  unsigned char * iv = NULL;
  size_t header_len = 0, cypher_key_len = 0, iv_len = 0, cypher_len = 0, tag_len = 0;
  json_t * j_header = NULL;

  if (jwe != NULL && jwe_str != NULL && jwe_str_len) {
    token = o_strndup(jwe_str, jwe_str_len);
    // Remove whitespaces and newlines
    tmp = str_replace(token, " ", "");
    o_free(token);
    token = tmp;
    tmp = str_replace(token, "\n", "");
    o_free(token);
    token = tmp;
    tmp = str_replace(token, "\t", "");
    o_free(token);
    token = tmp;
    tmp = str_replace(token, "\v", "");
    o_free(token);
    token = tmp;
    tmp = str_replace(token, "\f", "");
    o_free(token);
    token = tmp;
    tmp = str_replace(token, "\r", "");
    o_free(token);
    token = tmp;
    if (split_string(token, ".", &str_array) == 5 && !o_strnullempty(str_array[0]) && !o_strnullempty(str_array[2]) && !o_strnullempty(str_array[3]) && !o_strnullempty(str_array[4])) {
      // Check if all elements 0, 2 and 3 are base64url encoded
      if (o_base64url_decode((unsigned char *)str_array[0], o_strlen(str_array[0]), NULL, &header_len) &&
         (o_strnullempty(str_array[1]) || o_base64url_decode((unsigned char *)str_array[1], o_strlen(str_array[1]), NULL, &cypher_key_len)) &&
          o_base64url_decode((unsigned char *)str_array[2], o_strlen(str_array[2]), NULL, &iv_len) &&
          o_base64url_decode((unsigned char *)str_array[3], o_strlen(str_array[3]), NULL, &cypher_len) &&
          o_base64url_decode((unsigned char *)str_array[4], o_strlen(str_array[4]), NULL, &tag_len)) {
        ret = RHN_OK;
        jwe->token_mode = R_JSON_MODE_COMPACT;
        do {
          // Decode header
          if ((str_header = o_malloc(header_len+4)) == NULL) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error allocating resources for str_header");
            ret = RHN_ERROR_MEMORY;
            break;
          }

          if (!o_base64url_decode((unsigned char *)str_array[0], o_strlen(str_array[0]), (unsigned char *)str_header, &header_len)) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error o_base64url_decode str_header");
            ret = RHN_ERROR_PARAM;
            break;
          }
          str_header[header_len] = '\0';

          if ((j_header = json_loads(str_header, JSON_DECODE_ANY, NULL)) == NULL) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error json_loads str_header");
            ret = RHN_ERROR_PARAM;
            break;
          }

          if (r_jwe_extract_header(jwe, j_header, parse_flags, x5u_flags) != RHN_OK) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - error extracting header params");
            ret = RHN_ERROR_PARAM;
            break;
          }
          json_decref(jwe->j_header);

          jwe->j_header = json_incref(j_header);

          // Decode iv
          if ((iv = o_malloc(iv_len+4)) == NULL) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error allocating resources for iv");
            ret = RHN_ERROR_MEMORY;
            break;
          }

          if (!o_base64url_decode((unsigned char *)str_array[2], o_strlen(str_array[2]), iv, &iv_len)) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error o_base64url_decode iv");
            ret = RHN_ERROR_PARAM;
            break;
          }

          if (r_jwe_set_iv(jwe, iv, iv_len) != RHN_OK) {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_compact_parsen - Error r_jwe_set_iv");
            ret = RHN_ERROR;
            break;
          }

          o_free(jwe->header_b64url);
          jwe->header_b64url = (unsigned char *)o_strdup(str_array[0]);
          o_free(jwe->aad_b64url);
          jwe->aad_b64url = (unsigned char *)o_strdup(str_array[0]);
          o_free(jwe->encrypted_key_b64url);
          jwe->encrypted_key_b64url = (unsigned char *)o_strdup(str_array[1]);
          o_free(jwe->iv_b64url);
          jwe->iv_b64url = (unsigned char *)o_strdup(str_array[2]);
          o_free(jwe->ciphertext_b64url);
          jwe->ciphertext_b64url = (unsigned char *)o_strdup(str_array[3]);
          o_free(jwe->auth_tag_b64url);
          jwe->auth_tag_b64url = (unsigned char *)o_strdup(str_array[4]);

        } while (0);
        json_decref(j_header);
        o_free(str_header);
        o_free(iv);
      } else {
        ret = RHN_ERROR_PARAM;
      }
    } else {
      ret = RHN_ERROR_PARAM;
    }
    free_string_array(str_array);
    o_free(token);
  } else {
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

int r_jwe_advanced_parse_json_t(jwe_t * jwe, json_t * jwe_json, uint32_t parse_flags, int x5u_flags) {
  int ret;
  size_t header_len = 0, cypher_key_len = 0, iv_len = 0, index = 0;;
  char * str_header = NULL;
  json_t * j_header = NULL, * j_recipient;
  unsigned char * iv = NULL;

  if (jwe != NULL && json_is_object(jwe_json)) {
    if (json_string_length(json_object_get(jwe_json, "protected")) &&
        json_string_length(json_object_get(jwe_json, "iv")) &&
        json_string_length(json_object_get(jwe_json, "ciphertext")) &&
        json_string_length(json_object_get(jwe_json, "tag"))) {
      ret = RHN_OK;
      r_jwe_set_cypher_key(jwe, NULL, 0);
      r_jwe_set_iv(jwe, NULL, 0);
      r_jwe_set_aad(jwe, NULL, 0);
      r_jwe_set_payload(jwe, NULL, 0);
      o_free(jwe->header_b64url);
      jwe->header_b64url = NULL;
      o_free(jwe->encrypted_key_b64url);
      jwe->encrypted_key_b64url = NULL;
      o_free(jwe->iv_b64url);
      jwe->iv_b64url = NULL;
      o_free(jwe->ciphertext_b64url);
      jwe->ciphertext_b64url = NULL;
      o_free(jwe->auth_tag_b64url);
      jwe->auth_tag_b64url = NULL;
      o_free(jwe->aad_b64url);
      jwe->aad_b64url = NULL;
      json_decref(jwe->j_header);
      jwe->j_header = json_object();
      json_decref(jwe->j_unprotected_header);
      jwe->j_unprotected_header = NULL;
      do {
        json_decref(jwe->j_json_serialization);
        if ((jwe->j_json_serialization = json_deep_copy(jwe_json)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error setting j_json_serialization");
          ret = RHN_ERROR;
          break;
        }

        if (json_object_get(jwe_json, "unprotected") != NULL && r_jwe_set_full_unprotected_header_json_t(jwe, json_object_get(jwe_json, "unprotected")) != RHN_OK) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error r_jwe_set_full_unprotected_header_json_t");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if (!o_base64url_decode((unsigned char *)json_string_value(json_object_get(jwe_json, "protected")), json_string_length(json_object_get(jwe_json, "protected")), NULL, &header_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error invalid protected base64");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if ((str_header = o_malloc(header_len+4)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error allocating resources for str_header");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if (!o_base64url_decode((unsigned char *)json_string_value(json_object_get(jwe_json, "protected")), json_string_length(json_object_get(jwe_json, "protected")), (unsigned char *)str_header, &header_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error invalid protected base64");
          ret = RHN_ERROR_PARAM;
          break;
        }
        str_header[header_len] = '\0';

        if ((j_header = json_loads(str_header, JSON_DECODE_ANY, NULL)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error json_loads str_header");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if (r_jwe_extract_header(jwe, j_header, parse_flags, x5u_flags) != RHN_OK) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - error extracting header params");
          ret = RHN_ERROR_PARAM;
          break;
        }
        json_decref(jwe->j_header);

        jwe->j_header = json_incref(j_header);

        // Decode iv
        if (!o_base64url_decode((unsigned char *)json_string_value(json_object_get(jwe_json, "iv")), json_string_length(json_object_get(jwe_json, "iv")), NULL, &iv_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error invalid iv base64");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if ((iv = o_malloc(iv_len+4)) == NULL) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error allocating resources for iv");
          ret = RHN_ERROR_MEMORY;
          break;
        }

        if (!o_base64url_decode((unsigned char *)json_string_value(json_object_get(jwe_json, "iv")), json_string_length(json_object_get(jwe_json, "iv")), iv, &iv_len)) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error o_base64url_decode iv");
          ret = RHN_ERROR_PARAM;
          break;
        }

        if (r_jwe_set_iv(jwe, iv, iv_len) != RHN_OK) {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error r_jwe_set_iv");
          ret = RHN_ERROR;
          break;
        }
        jwe->header_b64url = (unsigned char *)o_strdup(json_string_value(json_object_get(jwe_json, "protected")));
        jwe->ciphertext_b64url = (unsigned char *)o_strdup(json_string_value(json_object_get(jwe_json, "ciphertext")));
        jwe->auth_tag_b64url = (unsigned char *)o_strdup(json_string_value(json_object_get(jwe_json, "tag")));
        jwe->aad_b64url = (unsigned char *)o_strdup(json_string_value(json_object_get(jwe_json, "aad")));

      } while (0);
      json_decref(j_header);
      o_free(str_header);
      o_free(iv);
      if (ret == RHN_OK) {
        if (json_array_size(json_object_get(jwe_json, "recipients"))) {
          jwe->token_mode = R_JSON_MODE_GENERAL;
          json_array_foreach(json_object_get(jwe_json, "recipients"), index, j_recipient) {
            if (!json_is_object(j_recipient)) {
              y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Invalid recipient at index %zu, must be a JSON object", index);
              ret = RHN_ERROR_PARAM;
              break;
            } else {
              if (!o_base64url_decode((const unsigned char*)json_string_value(json_object_get(j_recipient, "encrypted_key")), json_string_length(json_object_get(j_recipient, "encrypted_key")), NULL, &cypher_key_len)) {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error at index %zu, invalid encrypted_key base64 %s", index);
                ret = RHN_ERROR_PARAM;
                break;
              }
              if (json_object_get(j_recipient, "header") != NULL && !json_is_object(json_object_get(j_recipient, "header"))) {
                y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Invalid header at index %zu, must be a JSON object", index);
                ret = RHN_ERROR_PARAM;
                break;
              }
            }
          }
        } else {
          jwe->token_mode = R_JSON_MODE_FLATTENED;
          jwe->encrypted_key_b64url = (unsigned char *)o_strdup(json_string_value(json_object_get(jwe_json, "encrypted_key")));
          if (json_object_get(jwe_json, "header") == NULL || r_jwe_extract_header(jwe, json_object_get(jwe_json, "header"), parse_flags, x5u_flags) == RHN_OK) {
            json_object_update_missing(jwe->j_header, json_object_get(jwe_json, "header"));
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - error extracting header params");
            ret = RHN_ERROR_PARAM;
          }
        }
      }
    } else {
      y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error invalid content");
      ret = RHN_ERROR_PARAM;
    }
  } else {
    y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_parse_json_t - Error input parameters");
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

int r_jwe_set_aad(jwe_t * jwe, const unsigned char * aad, size_t aad_len) {
  int ret;
  unsigned char * aad_b64 = NULL;
  size_t aad_b64_len = 0;

  if (jwe != NULL) {
    o_free(jwe->aad_b64url);
    jwe->aad_b64url = NULL;
    o_free(jwe->aad);
    if (aad != NULL && aad_len) {
      if ((jwe->aad = o_malloc(aad_len)) != NULL) {
        memcpy(jwe->aad, aad, aad_len);
        jwe->aad_len = aad_len;
        if ((aad_b64 = o_malloc(jwe->aad_len*2)) != NULL) {
          if (o_base64url_encode(jwe->aad, jwe->aad_len, aad_b64, &aad_b64_len)) {
            o_free(jwe->aad_b64url);
            jwe->aad_b64url = (unsigned char *)o_strndup((const char *)aad_b64, aad_b64_len);
            ret = RHN_OK;
          } else {
            y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_aad - Error o_base64url_encode aad_b64");
            ret = RHN_ERROR;
          }
          o_free(aad_b64);
        } else {
          y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_aad - Error allocating resources for aad_b64");
          ret = RHN_ERROR_MEMORY;
        }
        ret = RHN_OK;
      } else {
        y_log_message(Y_LOG_LEVEL_ERROR, "r_jwe_set_aad - Error allocating resources for aad");
        ret = RHN_ERROR_MEMORY;
      }
    } else {
      jwe->aad = NULL;
      jwe->aad_len = 0;
      ret = RHN_OK;
    }
  } else {
    ret = RHN_ERROR_PARAM;
  }
  return ret;
}

Project: rhonabwy
File: jwe.c

static int _r_concat_kdf(jwe_t * jwe, jwa_alg alg, const gnutls_datum_t * Z, gnutls_datum_t * kdf) {
  int ret = RHN_OK;
  unsigned char * apu_dec = NULL, * apv_dec = NULL;
  const char * alg_id = alg==R_JWA_ALG_ECDH_ES?r_jwa_enc_to_str(jwe->enc):r_jwa_alg_to_str(alg),
             * apu = r_jwe_get_header_str_value(jwe, "apu"),
             * apv = r_jwe_get_header_str_value(jwe, "apv");
  size_t apu_dec_len = 0, apv_dec_len = 0, alg_id_len = o_strlen(alg_id), key_data_len = 0;

  kdf->data = NULL;
  kdf->size = 0;
  do {
    if ((kdf->data = o_malloc(4+Z->size)) == NULL) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error malloc kdf->data");
      ret = RHN_ERROR_MEMORY;
      break;
    }

    memset(kdf->data, 0, 3);
    memset(kdf->data+3, 1, 1);
    memcpy(kdf->data+4, Z->data, Z->size);
    kdf->size = 4+Z->size;

    if ((kdf->data = o_realloc(kdf->data, kdf->size+4+alg_id_len)) == NULL) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error realloc kdf->data (1)");
      ret = RHN_ERROR_MEMORY;
      break;
    }

    memset(kdf->data+kdf->size, 0, 3);
    memset(kdf->data+kdf->size+3, (uint8_t)alg_id_len, 1);
    memcpy(kdf->data+kdf->size+4, alg_id, alg_id_len);
    kdf->size += 4+alg_id_len;

    if (!o_strnullempty(apu)) {
      if ((apu_dec = o_malloc(o_strlen(apu))) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error malloc apu_dec");
        ret = RHN_ERROR_MEMORY;
        break;
      }

      if (!o_base64url_decode((const unsigned char *)apu, o_strlen(apu), apu_dec, &apu_dec_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error o_base64url_decode apu");
        ret = RHN_ERROR;
        break;
      }
    }

    if ((kdf->data = o_realloc(kdf->data, kdf->size+4+apu_dec_len)) == NULL) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error realloc kdf->data (2)");
      ret = RHN_ERROR_MEMORY;
      break;
    }

    kdf->data[kdf->size] = (unsigned char)(apu_dec_len>>24) & 0xFF;
    kdf->data[kdf->size+1] = (unsigned char)(apu_dec_len>>16) & 0xFF;
    kdf->data[kdf->size+2] = (unsigned char)(apu_dec_len>>8) & 0xFF;
    kdf->data[kdf->size+3] = (unsigned char)(apu_dec_len) & 0xFF;
    if (apu_dec_len) {
      memcpy(kdf->data+kdf->size+4, apu_dec, apu_dec_len);
    }
    kdf->size += apu_dec_len+4;

    if (!o_strnullempty(apv)) {
      if ((apv_dec = o_malloc(o_strlen(apv))) == NULL) {
        y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error malloc apv_dec");
        ret = RHN_ERROR_MEMORY;
        break;
      }

      if (!o_base64url_decode((const unsigned char *)apv, o_strlen(apv), apv_dec, &apv_dec_len)) {
        y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error o_base64url_decode apv");
        ret = RHN_ERROR;
        break;
      }
    }

    if ((kdf->data = o_realloc(kdf->data, kdf->size+4+apv_dec_len)) == NULL) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error realloc kdf->data (3)");
      ret = RHN_ERROR_MEMORY;
      break;
    }

    kdf->data[kdf->size] = (unsigned char)(apv_dec_len>>24) & 0xFF;
    kdf->data[kdf->size+1] = (unsigned char)(apv_dec_len>>16) & 0xFF;
    kdf->data[kdf->size+2] = (unsigned char)(apv_dec_len>>8) & 0xFF;
    kdf->data[kdf->size+3] = (unsigned char)(apv_dec_len) & 0xFF;
    if (apv_dec_len) {
      memcpy(kdf->data+kdf->size+4, apv_dec, apv_dec_len);
    }
    kdf->size += apv_dec_len+4;

    if (alg == R_JWA_ALG_ECDH_ES) {
      key_data_len = _r_get_key_size(jwe->enc)*8;
    } else if (alg == R_JWA_ALG_ECDH_ES_A128KW) {
      key_data_len = 16*8;
    } else if (alg == R_JWA_ALG_ECDH_ES_A192KW) {
      key_data_len = 24*8;
    } else if (alg == R_JWA_ALG_ECDH_ES_A256KW) {
      key_data_len = 32*8;
    }

    if (!key_data_len) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error invalid keydatalen");
      ret = RHN_ERROR;
      break;
    }

    if ((kdf->data = o_realloc(kdf->data, kdf->size+4)) == NULL) {
      y_log_message(Y_LOG_LEVEL_ERROR, "_r_concat_kdf - Error realloc kdf->data (4)");
      ret = RHN_ERROR_MEMORY;
      break;
    }

    kdf->data[kdf->size] = (unsigned char)(key_data_len>>24) & 0xFF;
    kdf->data[kdf->size+1] = (unsigned char)(key_data_len>>16) & 0xFF;
    kdf->data[kdf->size+2] = (unsigned char)(key_data_len>>8) & 0xFF;
    kdf->data[kdf->size+3] = (unsigned char)(key_data_len) & 0xFF;
    kdf->size += 4;

  } while (0);

  o_free(apu_dec);
  o_free(apv_dec);

  if (ret != RHN_OK) {
    o_free(kdf->data);
    kdf->data = NULL;
    kdf->size = 0;
  }

  return ret;
}