Alt-Crypt-OpenSSL-PKCS12-Broadbean

 view release on metacpan or  search on metacpan

PKCS12.xs  view on Meta::CPAN

  } else {
    if (aparamtype == V_ASN1_SEQUENCE)
      pbe = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBEPARAM));
      if (pbe == NULL) {
        BIO_puts(bio, ", <unsupported parameters>");
        goto done;
      }
      if (parameters_hash) {
        long int val = ASN1_INTEGER_get(pbe->iter);
        SV * iteration = newSViv(val);
        if((hv_store(parameters_hash, "iteration", strlen("iteration"), iteration, 0)) == NULL)
          croak("unable to add MAC to the parameters_hash");
      } else
        BIO_printf(bio, ", Iteration %ld", ASN1_INTEGER_get(pbe->iter));
      PBEPARAM_free(pbe);
  }
  done:
  if(!parameters_hash)
    BIO_puts(bio, "\n");
  return 1;
}

MODULE = Crypt::OpenSSL::PKCS12    PACKAGE = Crypt::OpenSSL::PKCS12

PROTOTYPES: DISABLE

BOOT:
{
  HV *stash;
  char *name;
  int i;

  struct { char *n; I32 v; } Crypt__OpenSSL__PKCS12__const[] = {
    {"NOKEYS", NOKEYS},
    {"NOCERTS", NOCERTS},
    {"INFO", INFO},
    {"CLCERTS", CLCERTS},
    {"CACERTS", CACERTS},
    {Nullch,0}
  };

  OpenSSL_add_all_algorithms();

  stash = gv_stashpvn("Crypt::OpenSSL::PKCS12", 22, TRUE);

  for (i = 0; (name = Crypt__OpenSSL__PKCS12__const[i].n); i++) {
    newCONSTSUB(stash, name, newSViv(Crypt__OpenSSL__PKCS12__const[i].v));
  }
}

Crypt::OpenSSL::PKCS12
new(class)
  SV  *class

  CODE:

  if ((RETVAL = PKCS12_new()) == NULL) {
    croak("Couldn't create PKCS12_new() for class %" SVf "\n", SVfARG(class));
  }

  OUTPUT:
  RETVAL

IV legacy_support(class)
  SV *class;

  CODE:
  RETVAL = 1;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
  if (legacy)
      RETVAL = 1;
  else
      RETVAL = 0;
#endif
  OUTPUT:
  RETVAL

Crypt::OpenSSL::PKCS12
new_from_string(class, string)
  SV  *class
  SV  *string

  ALIAS:
  new_from_file = 1

  PREINIT:
  BIO *bio;
  STRLEN str_len;
  char *str_ptr;
  CODE:

  SvGETMAGIC(string);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
  /* FIXME: There should likely be an option for whether to load the legacy provider */
  legacy = OSSL_PROVIDER_load(NULL, "legacy");
  if (legacy == NULL) {
      warn("Failed to load Legacy provider\n");
  }
  deflt = OSSL_PROVIDER_load(NULL, "default");
  if (deflt == NULL) {
      OSSL_PROVIDER_unload(legacy);
      croak("Failed to load Default provider\n");
  }
#endif

  if (SvPOKp(string) || SvNOKp(string) || SvIOKp(string)) {
    if (ix == 1) {
      /* We are not looking up the SV's UTF8 bit because BIO_new_file() accepts
       * filename like syscall fopen() which mainly may accept octet sequences
       * for UTF-8 in C char*. That's what we get from using SvPV(). Also,
       * using SvPV() is not a bug if ASCII input is only allowed. */
      str_ptr = SvPV(string, str_len);
    } else {
      /* To avoid encoding mess, caller is not allowed to provide octets from
       * UTF-8 encoded strings. BIO_new_mem_buf() needs octet input only. */
      if (SvUTF8(string)) {
        croak("PKCS12_new_from: Source string must not be UTF-8 encoded (please use octets)");
      }
      str_ptr = SvPV(string, str_len);
    }
  } else {
    croak("PKCS12_new_from: Invalid Perl type for string or file was passed (0x%x).", (unsigned int)SvFLAGS(string));
  }

  if (!str_ptr || !str_len) croak("PKCS12_new_from: No string or file was passed.");

  if (ix == 1) {
    bio = BIO_new_file(str_ptr, "rb");
  } else {
    bio = BIO_new_mem_buf(str_ptr, str_len);
  }

  if (!bio) croak("Failed to create BIO");

  /* this can come in any number of ways */
  if ((RETVAL = d2i_PKCS12_bio(bio, 0)) == NULL) {
    BIO_free_all(bio);
    croak("%" SVf ": Couldn't create PKCS12 from d2i_PKCS12_BIO(): %s", SVfARG(class), ssl_error(aTHX));
  }

  BIO_free_all(bio);

  OUTPUT:
  RETVAL

# This is called at per-object destruction time.
void
DESTROY(pkcs12)
  Crypt::OpenSSL::PKCS12 pkcs12;

  CODE:
  if (pkcs12) {
    PKCS12_free(pkcs12);
  }

# This is called via an END block in the Perl module to clean up initialization that happened in BOOT.
void
__PKCS12_cleanup(void)
  CODE:

  CRYPTO_cleanup_all_ex_data();
  ERR_free_strings();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
  ERR_remove_state(0);
#endif
  EVP_cleanup();

SV*
as_string(pkcs12)
  Crypt::OpenSSL::PKCS12 pkcs12;

  PREINIT:
  BIO *bio;

  CODE:

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  if (!(i2d_PKCS12_bio(bio, pkcs12))) {
    sv_bio_error(aTHX_ bio);
    croak("i2d_PKCS12_bio: %s", ssl_error(aTHX));
  }

  RETVAL = extractBioString(aTHX_ bio);

  OUTPUT:
  RETVAL

SV*
mac_ok(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  CODE:

  if (!(PKCS12_verify_mac(pkcs12, pwd, strlen(pwd)))) {
    croak("PKCS12_verify_mac: \n%s", ssl_error(aTHX));
  }

  RETVAL = (PKCS12_verify_mac(pkcs12, pwd, strlen(pwd))) ? &PL_sv_yes : &PL_sv_no;

  OUTPUT:
  RETVAL

SV*
changepass(pkcs12, oldpwd = "", newpwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *oldpwd
  char *newpwd

  CODE:

  if (!(PKCS12_newpass(pkcs12, oldpwd, newpwd))) {
    warn("PKCS12_newpass: %s %s\n%s", oldpwd, newpwd, ssl_error(aTHX));
    RETVAL = &PL_sv_no;
  } else {
    RETVAL = &PL_sv_yes;
  }

  OUTPUT:
  RETVAL

SV*
create(pkcs12, cert_chain_pem = "", pk = "", pass = 0, file = 0, name = "PKCS12 Certificate")
  char *cert_chain_pem
  char *pk
  char *pass
  char *file
  char *name

  PREINIT:
  FILE *fp;
  EVP_PKEY* pkey;
  PKCS12 *p12;
  STACK_OF(X509) *cert_chain = NULL;

  CODE:

  pkey       = _load_pkey(pk, PEM_read_bio_PrivateKey);
  cert_chain = _load_cert_chain(cert_chain_pem, PEM_X509_INFO_read_bio);
  p12        = PKCS12_create(pass, name, pkey, sk_X509_shift(cert_chain), cert_chain, 0, 0, 0, 0, 0);

  if (!p12) {
    ERR_print_errors_fp(stderr);
    croak("Error creating PKCS#12 structure\n");
  }

  if (!(fp = fopen(file, "wb"))) {
    ERR_print_errors_fp(stderr);
    croak("Error opening file %s\n", file);
  }

  i2d_PKCS12_fp(fp, p12);
  PKCS12_free(p12);
  fclose(fp);

  RETVAL = &PL_sv_yes;

  OUTPUT:
  RETVAL


SV*
create_as_string(pkcs12, cert_chain_pem = "", pk = "", pass = 0, name = "PKCS12 Certificate")
  char *cert_chain_pem
  char *pk
  char *pass
  char *name

  PREINIT:
  BIO *bio;
  EVP_PKEY* pkey;
  PKCS12 *p12;
  STACK_OF(X509) *cert_chain = NULL;

  CODE:

  pkey       = _load_pkey(pk, PEM_read_bio_PrivateKey);
  cert_chain = _load_cert_chain(cert_chain_pem, PEM_X509_INFO_read_bio);
  p12        = PKCS12_create(pass, name, pkey, sk_X509_shift(cert_chain), cert_chain, 0, 0, 0, 0, 0);

  if (!p12) {
    ERR_print_errors_fp(stderr);
    croak("Error creating PKCS#12 structure\n");
  }

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));
  i2d_PKCS12_bio(bio, p12);

  RETVAL = extractBioString(aTHX_ bio);
  PKCS12_free(p12);

  OUTPUT:
  RETVAL

SV*
certificate(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  PREINIT:
  BIO *bio;
  STACK_OF(PKCS7) *asafes = NULL;

  CODE:

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  if ((asafes = PKCS12_unpack_authsafes(pkcs12)) == NULL)
        RETVAL = newSVpvn("",0);

  dump_certs_keys_p12(aTHX_ bio, pkcs12, pwd, strlen(pwd), CLCERTS|NOKEYS, NULL, NULL);

  RETVAL = extractBioString(aTHX_ bio);

  OUTPUT:
  RETVAL

SV*
ca_certificate(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  PREINIT:
  BIO *bio;

  CODE:

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  PKCS12_unpack_authsafes(pkcs12);

  dump_certs_keys_p12(aTHX_ bio, pkcs12, pwd, strlen(pwd), CACERTS|NOKEYS, NULL, NULL);

  RETVAL = extractBioString(aTHX_ bio);

  OUTPUT:
  RETVAL

SV*
private_key(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  PREINIT:
  BIO *bio;

  CODE:

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  PKCS12_unpack_authsafes(pkcs12);

  dump_certs_keys_p12(aTHX_ bio, pkcs12, pwd, strlen(pwd), NOCERTS, NULL, NULL);

  RETVAL = extractBioString(aTHX_ bio);

  OUTPUT:
  RETVAL

HV* info_as_hash(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  PREINIT:
  BIO *bio;
  STACK_OF(PKCS7) *asafes = NULL;

  CONST_ASN1_INTEGER *tmaciter;
#if OPENSSL_VERSION_NUMBER > 0x10100000L
  SV *value;
  CONST_X509_ALGOR *macalgid;
  CONST_ASN1_OBJECT *macobj;
  CONST_ASN1_OCTET_STRING *tmac;
  CONST_ASN1_OCTET_STRING *tsalt;
#endif

  CODE:
  RETVAL = newHV();

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  if ((asafes = PKCS12_unpack_authsafes(pkcs12)) == NULL)
        RETVAL = newHV();
  HV * mac = newHV();
#if OPENSSL_VERSION_NUMBER > 0x10100000L
  PKCS12_get0_mac(&tmac, &macalgid, &tsalt, &tmaciter, pkcs12);
  /* current hash algorithms do not use parameters so extract just name,
     in future alg_print() may be needed */
  X509_ALGOR_get0(&macobj, NULL, NULL, macalgid);
  i2a_ASN1_OBJECT(bio, macobj);
  value = extractBioString(aTHX_ bio);
  if((hv_store(mac, "digest", strlen("digest"), value, 0)) == NULL)
    croak("unable to add digest to the hash");
#else
  tmaciter = pkcs12->mac->iter;
#endif
  SV * mac_iteration = newSViv (tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);

  if((hv_store(mac, "iteration", strlen("iteration"), mac_iteration, 0)) == NULL)
    croak("unable to add iteration to the hash");
  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));
  /* BIO_printf(bio, "MAC length: %ld, salt length: %ld", */
#if OPENSSL_VERSION_NUMBER > 0x10100000L
  SV * mac_len = newSViv(tmac != NULL ? ASN1_STRING_length(tmac) : 0L);
  SV * salt_len = newSViv(tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L);

  if((hv_store(mac, "length", 6, mac_len, 0)) == NULL)
    croak("unable to add length to the hash");
#else
  SV * salt_len = newSViv((pkcs12)->mac ? pkcs12->mac->salt->length : 0L);
#endif

  if((hv_store(mac, "salt_length", strlen("salt_length"), INT2PTR(SV*, salt_len), 0)) == NULL)
    croak("unable to add salt_length to the hash");

  if((hv_store(RETVAL, "mac", strlen("mac"), newRV_inc((SV *) mac), 0)) == NULL)
    croak("unable to add MAC to the hash");
  dump_certs_keys_p12(aTHX_ bio, pkcs12, pwd, strlen(pwd), INFO, NULL, RETVAL);

  SV * end = extractBioString(aTHX_ bio);

  if (SvPOK(end)) {
    if (SvCUR(end) != 0)
      printf("BIO %s\n", SvPVbyte_nolen(end));
      warn("bio from info_as_hash should be zero length - report issue");
  }

  sv_2mortal((SV*)RETVAL);

  OUTPUT:
  RETVAL

SV*
info(pkcs12, pwd = "")
  Crypt::OpenSSL::PKCS12 pkcs12
  char *pwd

  PREINIT:
  BIO *bio;
  STACK_OF(PKCS7) *asafes = NULL;

  CONST_ASN1_INTEGER *tmaciter;
#if OPENSSL_VERSION_NUMBER > 0x10100000L
  CONST_X509_ALGOR *macalgid;
  CONST_ASN1_OBJECT *macobj;
  CONST_ASN1_OCTET_STRING *tmac;
  CONST_ASN1_OCTET_STRING *tsalt;
#endif
  CODE:

  CHECK_OPEN_SSL(bio = BIO_new(BIO_s_mem()));

  if ((asafes = PKCS12_unpack_authsafes(pkcs12)) == NULL)
        RETVAL = newSVpvn("",0);
#if OPENSSL_VERSION_NUMBER > 0x10100000L
  PKCS12_get0_mac(&tmac, &macalgid, &tsalt, &tmaciter, pkcs12);
  /* current hash algorithms do not use parameters so extract just name,
     in future alg_print() may be needed */
  X509_ALGOR_get0(&macobj, NULL, NULL, macalgid);
  BIO_puts(bio, "MAC: ");
  i2a_ASN1_OBJECT(bio, macobj);
  /* current hash algorithms do not use parameters so extract just name,
     in future alg_print() may be needed */
  BIO_printf(bio, ", Iteration %ld\n",
        tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);
  BIO_printf(bio, "MAC length: %ld, salt length: %ld\n",
        tmac != NULL ? ASN1_STRING_length(tmac) : 0L,
        tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L);
#else
  tmaciter = pkcs12->mac->iter;
  BIO_printf(bio, "MAC Iteration %ld\n",
        tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);
  /* If we enter empty password try no password first */
  if (!PKCS12_verify_mac(pkcs12, pwd, -1)) {
    BIO_printf(bio, "Mac verify error: invalid password?\n");
    ERR_print_errors(bio);
    goto end;
  }
  BIO_printf(bio, "MAC verified OK\n");
  end:
#endif
  dump_certs_keys_p12(aTHX_ bio, pkcs12, pwd, strlen(pwd), INFO, NULL, NULL);

  RETVAL = extractBioString(aTHX_ bio);

  OUTPUT:
  RETVAL



( run in 0.950 second using v1.01-cache-2.11-cpan-13bb782fe5a )