CK_FUNCTION_LIST_PTR p11;
uint8_t *cert_id;
size_t cert_id_len;
- CK_MECHANISM_TYPE mech;
#endif
krb5_boolean defer_id_prompt;
pkinit_deferred_id *deferred_ids;
#if OPENSSL_VERSION_NUMBER < 0x30000000L
/* OpenSSL 3.0 changes several preferred function names. */
#define EVP_PKEY_parameters_eq EVP_PKEY_cmp_parameters
-#define EVP_MD_CTX_get0_md EVP_MD_CTX_md
#define EVP_PKEY_get_size EVP_PKEY_size
#define EVP_PKEY_get_bits EVP_PKEY_bits
STACK_OF(X509) * cert_stack = NULL;
ASN1_OCTET_STRING *digest_attr = NULL;
EVP_MD_CTX *ctx;
- const EVP_MD *md_tmp = NULL;
- unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
- unsigned char *digestInfo_buf = NULL, *abuf = NULL;
- unsigned int md_len, md_len2, alen, digestInfo_len;
+ unsigned char md_data[EVP_MAX_MD_SIZE], *abuf = NULL;
+ unsigned int md_len, alen;
STACK_OF(X509_ATTRIBUTE) * sk;
unsigned char *sig = NULL;
unsigned int sig_len = 0;
X509_ALGOR *alg = NULL;
- ASN1_OCTET_STRING *digest = NULL;
- unsigned int alg_len = 0, digest_len = 0;
- unsigned char *y = NULL;
ASN1_OBJECT *oid = NULL, *oid_copy;
int sig_alg_id;
goto cleanup;
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
EVP_DigestUpdate(ctx, data, data_len);
- md_tmp = EVP_MD_CTX_get0_md(ctx);
EVP_DigestFinal_ex(ctx, md_data, &md_len);
EVP_MD_CTX_free(ctx);
if (abuf == NULL)
goto cleanup2;
-#ifndef WITHOUT_PKCS11
- /*
- * Some tokens can only do RSAEncryption without a hash. To compute
- * sha256WithRSAEncryption, encode the algorithm ID for the hash
- * function and the hash value into an ASN.1 value of type DigestInfo:
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm AlgorithmIdentifier,
- * digest OCTET STRING
- * }
- */
- if (id_cryptoctx->pkcs11_method == 1 &&
- id_cryptoctx->mech == CKM_RSA_PKCS) {
- pkiDebug("mech = CKM_RSA_PKCS\n");
- ctx = EVP_MD_CTX_new();
- if (ctx == NULL)
- goto cleanup;
- EVP_DigestInit_ex(ctx, md_tmp, NULL);
- EVP_DigestUpdate(ctx, abuf, alen);
- EVP_DigestFinal_ex(ctx, md_data2, &md_len2);
- EVP_MD_CTX_free(ctx);
-
- alg = X509_ALGOR_new();
- if (alg == NULL)
- goto cleanup2;
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
- alg_len = i2d_X509_ALGOR(alg, NULL);
-
- digest = ASN1_OCTET_STRING_new();
- if (digest == NULL)
- goto cleanup2;
- ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
- digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
-
- digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
- V_ASN1_SEQUENCE);
- y = digestInfo_buf = malloc(digestInfo_len);
- if (digestInfo_buf == NULL)
- goto cleanup2;
- ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
- V_ASN1_UNIVERSAL);
- i2d_X509_ALGOR(alg, &y);
- i2d_ASN1_OCTET_STRING(digest, &y);
-#ifdef DEBUG_SIG
- pkiDebug("signing buffer\n");
- print_buffer(digestInfo_buf, digestInfo_len);
- print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
-#endif
- retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
- digestInfo_len, &sig, &sig_len);
- } else
-#endif
- {
- pkiDebug("mech = %s\n",
- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
- retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
- &sig, &sig_len);
- }
+ retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
+ &sig, &sig_len);
#ifdef DEBUG_SIG
print_buffer(sig, sig_len);
#endif
cleanup2:
if (p7si) {
-#ifndef WITHOUT_PKCS11
- if (id_cryptoctx->pkcs11_method == 1 &&
- id_cryptoctx->mech == CKM_RSA_PKCS) {
- free(digestInfo_buf);
- if (digest != NULL)
- ASN1_OCTET_STRING_free(digest);
- }
-#endif
if (alg != NULL)
X509_ALGOR_free(alg);
}
* Look for a key that's:
* 1. private
* 2. capable of the specified operation (usually signing or decrypting)
- * 3. RSA (this may be wrong but it's all we can do for now)
- * 4. matches the id of the cert we chose
+ * 3. matches the id of the cert we chose
*
* You must call pkinit_get_certs before calling pkinit_find_private_key
* (that's because we need the ID of the private key)
CK_OBJECT_CLASS cls;
CK_ATTRIBUTE attrs[4];
CK_ULONG count;
- CK_KEY_TYPE keytype;
unsigned int nattrs = 0;
int r;
#ifdef PKINIT_USE_KEY_USAGE
nattrs++;
#endif
- keytype = CKK_RSA;
- attrs[nattrs].type = CKA_KEY_TYPE;
- attrs[nattrs].pValue = &keytype;
- attrs[nattrs].ulValueLen = sizeof keytype;
- nattrs++;
-
attrs[nattrs].type = CKA_ID;
attrs[nattrs].pValue = id_cryptoctx->cert_id;
attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
}
#ifndef WITHOUT_PKCS11
+/*
+ * DER-encode a DigestInfo sequence containing the algorithm md and the digest
+ * mdbytes.
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING
+ * }
+ */
+static krb5_error_code
+encode_digestinfo(krb5_context context, const EVP_MD *md,
+ const uint8_t *mdbytes, size_t mdlen,
+ uint8_t **encoding_out, size_t *len_out)
+{
+ krb5_boolean ok = FALSE;
+ X509_ALGOR *alg = NULL;
+ ASN1_OCTET_STRING *digest = NULL;
+ uint8_t *buf, *p;
+ int alg_len, digest_len, len;
+
+ *encoding_out = NULL;
+ *len_out = 0;
+
+ alg = X509_ALGOR_new();
+ if (alg == NULL ||
+ !X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_nid(md)), V_ASN1_NULL, NULL))
+ goto cleanup;
+ alg_len = i2d_X509_ALGOR(alg, NULL);
+ if (alg_len < 0)
+ goto cleanup;
+
+ digest = ASN1_OCTET_STRING_new();
+ if (digest == NULL || !ASN1_OCTET_STRING_set(digest, mdbytes, mdlen))
+ goto cleanup;
+ digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
+ if (digest_len < 0)
+ goto cleanup;
+
+ len = ASN1_object_size(1, alg_len + digest_len, V_ASN1_SEQUENCE);
+ p = buf = malloc(len);
+ if (buf == NULL)
+ goto cleanup;
+ ASN1_put_object(&p, 1, alg_len + digest_len, V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL);
+ i2d_X509_ALGOR(alg, &p);
+ i2d_ASN1_OCTET_STRING(digest, &p);
+
+ *encoding_out = buf;
+ *len_out = len;
+ ok = TRUE;
+
+cleanup:
+ X509_ALGOR_free(alg);
+ ASN1_OCTET_STRING_free(digest);
+ if (!ok)
+ return oerr(context, 0, _("Failed to DER encode DigestInfo"));
+ return 0;
+}
+
+/* Extract the r and s values from a PKCS11 ECDSA signature and re-encode them
+ * in the DER representation of an ECDSA-Sig-Value for use in CMS. */
+static krb5_error_code
+convert_pkcs11_ecdsa_sig(krb5_context context,
+ const uint8_t *p11sig, unsigned int p11siglen,
+ uint8_t **sig_out, unsigned int *sig_len_out)
+{
+ krb5_boolean ok = FALSE;
+ BIGNUM *r = NULL, *s = NULL;
+ ECDSA_SIG *sig = NULL;
+ int len;
+ uint8_t *p;
+
+ *sig_out = NULL;
+ *sig_len_out = 0;
+
+ if (p11siglen % 2 != 0)
+ return EINVAL;
+
+ /* Extract the r and s values from the PKCS11 signature. */
+ r = BN_bin2bn(p11sig, p11siglen / 2, NULL);
+ s = BN_bin2bn(p11sig + p11siglen / 2, p11siglen / 2, NULL);
+ if (r == NULL || s == NULL)
+ goto cleanup;
+
+ /* Create an ECDSA-Sig-Value object and transfer ownership of r and s. */
+ sig = ECDSA_SIG_new();
+ if (sig == NULL || !ECDSA_SIG_set0(sig, r, s))
+ goto cleanup;
+ r = s = NULL;
+
+ /* DER-encode the ECDSA-Sig-Value object. */
+ len = i2d_ECDSA_SIG(sig, NULL);
+ if (len < 0)
+ goto cleanup;
+ p = *sig_out = malloc(len);
+ if (*sig_out == NULL)
+ goto cleanup;
+ *sig_len_out = len;
+ i2d_ECDSA_SIG(sig, &p);
+ ok = TRUE;
+
+cleanup:
+ BN_free(r);
+ BN_free(s);
+ ECDSA_SIG_free(sig);
+ if (!ok)
+ return oerr(context, 0, _("Failed to convert PKCS11 ECDSA signature"));
+ return 0;
+}
+
static krb5_error_code
pkinit_sign_data_pkcs11(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
unsigned char **sig,
unsigned int *sig_len)
{
+ krb5_error_code ret;
CK_OBJECT_HANDLE obj;
CK_ULONG len;
CK_MECHANISM mech;
- unsigned char *cp;
+ CK_SESSION_HANDLE session;
+ CK_FUNCTION_LIST_PTR p11;
+ CK_ATTRIBUTE attr;
+ CK_KEY_TYPE keytype;
+ EVP_MD_CTX *ctx;
+ const EVP_MD *md = EVP_sha256();
+ unsigned int mdlen;
+ uint8_t mdbuf[EVP_MAX_MD_SIZE], *dinfo = NULL, *sigbuf = NULL, *input;
+ size_t dinfo_len, input_len;
int r;
+ *sig = NULL;
+ *sig_len = 0;
+
if (pkinit_open_session(context, id_cryptoctx)) {
pkiDebug("can't open pkcs11 session\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
+ p11 = id_cryptoctx->p11;
+ session = id_cryptoctx->session;
- pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
+ ret = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
+ if (ret)
+ return ret;
+
+ attr.type = CKA_KEY_TYPE;
+ attr.pValue = &keytype;
+ attr.ulValueLen = sizeof(keytype);
+ r = p11->C_GetAttributeValue(session, obj, &attr, 1);
+ if (r) {
+ pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(r));
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
+
+ /*
+ * We would ideally use CKM_SHA256_RSA_PKCS and CKM_ECDSA_SHA256, but
+ * historically many cards seem to be confused about whether they are
+ * capable of mechanisms or not. To be safe we compute the digest
+ * ourselves and use CKM_RSA_PKCS and CKM_ECDSA.
+ */
+ ctx = EVP_MD_CTX_new();
+ if (ctx == NULL) {
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
+ EVP_DigestUpdate(ctx, data, data_len);
+ EVP_DigestFinal_ex(ctx, mdbuf, &mdlen);
+ EVP_MD_CTX_free(ctx);
- mech.mechanism = id_cryptoctx->mech;
+ if (keytype == CKK_RSA) {
+ /* For RSA we must also encode the digest in a DigestInfo sequence. */
+ mech.mechanism = CKM_RSA_PKCS;
+ ret = encode_digestinfo(context, md, mdbuf, mdlen, &dinfo, &dinfo_len);
+ if (ret)
+ goto cleanup;
+ input = dinfo;
+ input_len = dinfo_len;
+ } else if (keytype == CKK_EC) {
+ mech.mechanism = CKM_ECDSA;
+ input = mdbuf;
+ input_len = mdlen;
+ } else {
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ k5_setmsg(context, ret,
+ _("PKCS11 certificate has unsupported key type %lu"),
+ keytype);
+ goto cleanup;
+ }
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
- obj)) != CKR_OK) {
+ r = p11->C_SignInit(session, &mech, obj);
+ if (r != CKR_OK) {
pkiDebug("C_SignInit: %s\n", pkcs11err(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
/*
* get that. So guess, and if it's too small, re-malloc.
*/
len = PK_SIGLEN_GUESS;
- cp = malloc((size_t) len);
- if (cp == NULL)
- return ENOMEM;
+ sigbuf = k5alloc(len, &ret);
+ if (sigbuf == NULL)
+ goto cleanup;
- r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
- (CK_ULONG) data_len, cp, &len);
+ r = p11->C_Sign(session, input, input_len, sigbuf, &len);
if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
- free(cp);
+ free(sigbuf);
pkiDebug("C_Sign realloc %d\n", (int) len);
- cp = malloc((size_t) len);
- r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
- (CK_ULONG) data_len, cp, &len);
+ sigbuf = k5alloc(len, &ret);
+ if (sigbuf == NULL)
+ goto cleanup;
+ r = p11->C_Sign(session, input, input_len, sigbuf, &len);
}
if (r != CKR_OK) {
pkiDebug("C_Sign: %s\n", pkcs11err(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
- pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
- *sig_len = len;
- *sig = cp;
- return 0;
+ if (keytype == CKK_EC) {
+ /* PKCS11 ECDSA signatures must be re-encoded for CMS. */
+ ret = convert_pkcs11_ecdsa_sig(context, sigbuf, len, sig, sig_len);
+ } else {
+ *sig_len = len;
+ *sig = sigbuf;
+ sigbuf = NULL;
+ }
+
+cleanup:
+ free(dinfo);
+ free(sigbuf);
+ return ret;
}
#endif
return 0;
}
- /*
- * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
- * historically many cards seem to be confused about whether they are
- * capable of mechanisms or not. The safe thing seems to be to ignore the
- * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest
- * ourselves.
- */
- id_cryptoctx->mech = CKM_RSA_PKCS;
-
cls = CKO_CERTIFICATE;
attrs[0].type = CKA_CLASS;
attrs[0].pValue = &cls;
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMFoXDTMyMDkyMDIxMTEzMFowgacxCzAJ
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owgacxCzAJ
BgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1i
cmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwgSW5zZWN1cmUgUEtJTklUIEtl
cmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBk
byBub3QgdXNlIG90aGVyd2lzZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAM+lV5iaVats0yBFN4FBe6bovloNe3d0F9qMuhKqlECv6cFra75gSGmHJz6t
-GTK8zITU7sni429azTZC9IQnUt/2lW8dWzpZD1T5Vt1DYvYFqVzjhNfzeEDK88ig
-ENfzaX/cY2P76arJr0cewGaauzaux8heYW1CjBxWmk6kWq4aD+5jggchvBeOGEE2
-NkV3MPbXut8fu+3NzuuIG7Z0ilwQv+KUvQ8QQb9VCwdsDh/ERsQ4loC9P4jtuWCJ
-ikIE78GxDcOMoC1ftJtW/mBCS2iCHipXrp2BDDJMyHxZjHpl0VoDR7koWGtD3sos
-EwUkXVvWIuKs432h2dXQ+u8HaBsCAwEAAaOCARgwggEUMB0GA1UdDgQWBBT0F6X7
-1QRftDiSeNSY3bks3nK0IzCB1AYDVR0jBIHMMIHJgBT0F6X71QRftDiSeNSY3bks
-3nK0I6GBraSBqjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0
+ggEBAJv9Sbc2QSbHWnZjk55JfeOdPGUsmKOcT/N7C0/0mOQq4tUCmha7ntpBoIJd
+UBDhMQayG3QHruQX7aogtOx8hoLoLUaNKgxzEZ0OLbDRMc2M+vTDpBROITGI1KPv
+QtthlS4ocqKvqBCze66N9LufzAju61CyKdB3pCykPrgDVVScfsZ1t2zCbK0SF2cf
+ZAdIyCLoGLeQ95/NL3SIx0CX9gU47AVmBkSQ+LExJRhbUSIg+puKbqJ0XVILR1B2
+ezgik2ObFND0hsRUS4v8pKnIDz0HXR2AneTESY+atjbzzelGA2zH86p4tLg0PanQ
+4x4+gpkQhzSr5Cmi3QX4XahSrmUCAwEAAaOCARgwggEUMB0GA1UdDgQWBBSSP/pz
+leX5zVcZ9hpI5GG2eQ+pqjCB1AYDVR0jBIHMMIHJgBSSP/pzleX5zVcZ9hpI5GG2
+eQ+pqqGBraSBqjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0
dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoGA1UECgwDTUlUMSkwJwYDVQQLDCBJ
bnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAwwqcGtpbml0
IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQE
-AwIB/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBT2FJVPS+U
-0MXa1HUOETuUPrVff7VeIvyAPm9IgX1zNbCvktCc4d7ErNB3P5ng8aZz4MKqwzuX
-HVhUxbF7JKfyUI41lcixPG+k+U9mzBJaozWT+K1OhdUF//mGPxaxe5jyUhDiQArD
-/6vulX0/B+1iuIa1sCfoeelzqQcYHqhZdWn6bBdcDWNARHIXWs5zPeKA975+d5TW
-rofE7T8nNQJvcZoVjCSfcYXhP82D/0sA+wPCt3fgbBZdvJ89xwvIlzBtiwC++Zbe
-37Rt5av0+ykpR7nmh2jyG+ItzE73nYKdBrUI5J6JLSbUcQTw4jeXHwDULUHZ6fXg
-TBEM2v1VW4Df
+AwIB/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAfx04Uqh0D
+myOR1PSqEEbMWJxZXYoESnjjH4Co4doceVBTuKix/2lplD4wcvA7aMXpmkvGfP38
+dPrN1jvGd4bi/djTuxab9qB7rOeswAt+NyVHReUmuIMwgcW1UD7HXErg4EsOMjGD
+2XGhJYxGnwdURmnFwoO3yLLwo5K+C4rqPm3PbnI3W0sCA+IXepQTxuXK3dSplMMm
+0Pejw3es2s3oI9WaD2JRXvFuylw4UWYX+cyFRb+wN55Gh0rPVdxDhKCkbWNt/gTi
+/DbC+5pyQXkmy07OEGrmh4+5ae9hwejr9AukF2IZJB+oFP4i1mt9xyAOXImnWOzB
+SdHD08WHl5Gq
-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSB3T7ihe3JUeIKZI
+PCDqATKN/dNugQsaC5AKiBPC6ymhRANCAAQy0E88e1CX16/2wL2T+nE0pmlb7wBM
+0hOh6m3m2uDbVsAIRJfhEjHWsT2ODCoBvGDV6vBeIOUjE/Ro9EwnYBW5
+-----END PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIECDCCAvCgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSjELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
+MtBPPHtQl9ev9sC9k/pxNKZpW+8ATNIToept5trg21bACESX4RIx1rE9jgwqAbxg
+1erwXiDlIxP0aPRMJ2AVuaOCAWQwggFgMB0GA1UdDgQWBBR5MaRx7ub5YBwsS0CF
+Li18nsl49zCB1AYDVR0jBIHMMIHJgBSSP/pzleX5zVcZ9hpI5GG2eQ+pqqGBraSB
+qjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNV
+BAcMCUNhbWJyaWRnZTEMMAoGA1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQ
+S0lOSVQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3Vp
+dGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQEAwID6DAMBgNV
+HRMBAf8EAjAAMDkGA1UdEQQyMDCgLgYGKwYBBQICoCQwIqANGwtLUkJURVNULkNP
+TaERMA+gAwIBAaEIMAYbBHVzZXIwEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG
+9w0BAQsFAAOCAQEAfwlONLYPo0BNN2NyQZM3wkoldvFqidcoZiYALOcBcmllMP7H
+XQ/+en4TmbKR0RUJN6AjR9yEo92fHAYOB2L7AzR8AkOiRLjp/Pdg5kUHFTdKenTK
+DvpeiJELz9chk/vaMv1T9qvOwH2bVAyS8GrUc5n0ui5F61PrquLAmm+dpKyHDY60
+DdFaebS2gYsmy4bBv0mgcMZ+ZXnzXYmLNtdVQ3SgVGO7M8eyCqPbe/o0Lw4Gz+l0
+xgpFkptdlEogsOaJBzjrgWyBnWw6MkyyLiSY+iOxFpBGkwCxi1gtQwbcp4gMwaxc
+p5+JPM/JBfglBX1lpRhhxL8EGQvpryN9MT530w==
+-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
-FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
-A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
-dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMVoXDTMyMDkyMDIxMTEzMVowSjELMAkG
-A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
-U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtrvmBIaYcn
-Pq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE1/N4QMrz
-yKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOCByG8F44Y
-QTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiWgL0/iO25
-YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNHuShYa0Pe
-yiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCS
-OTfZununxFDxuThhIFDWEZ9p2qSqTrxKtKx4CDvdckz4kaKybiNZTW7Dlh6IwWta
-60eq98WrMHXYlSaN87r95lU0ug2RFJh4uLdq3a5NM/daIIjO0Bo86oC+8EBM961Q
-mCMe7dn9ngFK92msdqO+wfpAfvhSpBPtAjQovigirheiEoER/ov9t9/3mRi5OTkY
-8YfKT/z6XJrnOUIB3AgCdGyzSRvWLqLrbh7iAFVrm6Pq6D2nNr+mE9r5u7uFl3r8
-QeDgp0Unwd1ISWTHZlrP4bq29w7y2O+/2KV04Og8z+4zoGD4nRinuJBUdNqwAXVz
-dz6pXFWgLRD+9ddI5jB0
+MIIDZjCCAk4CAQgwDQYJKoZIhvcNAQELBQAwgacxCzAJBgNVBAYTAlVTMRYwFAYD
+VQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxDDAKBgNVBAoM
+A01JVDEpMCcGA1UECwwgSW5zZWN1cmUgUEtJTklUIEtlcmJlcm9zIHRlc3QgQ0Ex
+MzAxBgNVBAMMKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVy
+d2lzZTAeFw0yNDAyMTUwNDU5MDdaFw0zNTAxMjgwNDU5MDdaMEoxCzAJBgNVBAYT
+AlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRQwEgYDVQQKDAtLUkJURVNULkNP
+TTENMAsGA1UEAwwEdXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJv9Sbc2QSbHWnZjk55JfeOdPGUsmKOcT/N7C0/0mOQq4tUCmha7ntpBoIJdUBDh
+MQayG3QHruQX7aogtOx8hoLoLUaNKgxzEZ0OLbDRMc2M+vTDpBROITGI1KPvQtth
+lS4ocqKvqBCze66N9LufzAju61CyKdB3pCykPrgDVVScfsZ1t2zCbK0SF2cfZAdI
+yCLoGLeQ95/NL3SIx0CX9gU47AVmBkSQ+LExJRhbUSIg+puKbqJ0XVILR1B2ezgi
+k2ObFND0hsRUS4v8pKnIDz0HXR2AneTESY+atjbzzelGA2zH86p4tLg0PanQ4x4+
+gpkQhzSr5Cmi3QX4XahSrmUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAau8fw4h1
+hp4/gp7l+AXvq+9E/a2y2Np+H8BmlRIg8ZLyKjRR6iPjcUwFWUteSSBsFzcc+/5V
+/Qs9gAW4nRIb9zY/sPO3KMAjJGKaP3u8xWkrfVZzaqPkfOWa5RDkh9AtvpN/fVLH
+dC+hC1xlXtjJ/YugJD6OA66sxdyTjR/v++0mqaTQyTI29HqtTc9LUcpbC1OYzxS3
+8vlZZgieRU0UlBvpsR0AqCaTZPgcrIvJ0EVIk6XzgOWJAptAe3tFEVrHtZJAQG04
+TI7NN/zw17O9Sn8NVEB4RSw6CFZeEVBBfCZL99HveEd8WPU0zgYceuVl/UCpQFNi
+Av6/+n+/6KwHXg==
-----END CERTIFICATE-----
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMFoXDTMyMDkyMDIxMTEzMFowSTELMAkG
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSTELMAkG
A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
U1QuQ09NMQwwCgYDVQQDDANLREMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQDPpVeYmlWrbNMgRTeBQXum6L5aDXt3dBfajLoSqpRAr+nBa2u+YEhphyc+
-rRkyvMyE1O7J4uNvWs02QvSEJ1Lf9pVvHVs6WQ9U+VbdQ2L2Balc44TX83hAyvPI
-oBDX82l/3GNj++mqya9HHsBmmrs2rsfIXmFtQowcVppOpFquGg/uY4IHIbwXjhhB
-NjZFdzD217rfH7vtzc7riBu2dIpcEL/ilL0PEEG/VQsHbA4fxEbEOJaAvT+I7blg
-iYpCBO/BsQ3DjKAtX7SbVv5gQktogh4qV66dgQwyTMh8WYx6ZdFaA0e5KFhrQ97K
-LBMFJF1b1iLirON9odnV0PrvB2gbAgMBAAGjggFzMIIBbzAdBgNVHQ4EFgQU9Bel
-+9UEX7Q4knjUmN25LN5ytCMwgdQGA1UdIwSBzDCByYAU9Bel+9UEX7Q4knjUmN25
-LN5ytCOhga2kgaowgacxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl
+AoIBAQCb/Um3NkEmx1p2Y5OeSX3jnTxlLJijnE/zewtP9JjkKuLVApoWu57aQaCC
+XVAQ4TEGsht0B67kF+2qILTsfIaC6C1GjSoMcxGdDi2w0THNjPr0w6QUTiExiNSj
+70LbYZUuKHKir6gQs3uujfS7n8wI7utQsinQd6QspD64A1VUnH7GdbdswmytEhdn
+H2QHSMgi6Bi3kPefzS90iMdAl/YFOOwFZgZEkPixMSUYW1EiIPqbim6idF1SC0dQ
+dns4IpNjmxTQ9IbEVEuL/KSpyA89B10dgJ3kxEmPmrY2883pRgNsx/OqeLS4ND2p
+0OMePoKZEIc0q+Qpot0F+F2oUq5lAgMBAAGjggFzMIIBbzAdBgNVHQ4EFgQUkj/6
+c5Xl+c1XGfYaSORhtnkPqaowgdQGA1UdIwSBzDCByYAUkj/6c5Xl+c1XGfYaSORh
+tnkPqaqhga2kgaowgacxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl
dHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwg
SW5zZWN1cmUgUEtJTklUIEtlcmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5p
dCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZYIBATALBgNVHQ8E
BAMCA+gwDAYDVR0TAQH/BAIwADBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgDRsL
S1JCVEVTVC5DT02hIDAeoAMCAQKhFzAVGwZrcmJ0Z3QbC0tSQlRFU1QuQ09NMBIG
-A1UdJQQLMAkGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBAJZd7v5ZOMs8Y3ht
-Kmtql8rKs0Jee73gVHYw3LXxJfHjIiNGdexxuWJ6Hy9gFnfwSco+15HP3MxMBkau
-TKo3i1+Kwf+lc7gIZ0g/CEnYOx2smHGd9yGudWypunYLjGWfH/2M8/Wu1gZDTxQ1
-pNMQZ2pPLL/C6c6vYpVQJ5cA0RSh/SC5IbOESUpZaFFMYxF5TNz+28/lDr/rN41O
-miklos6cH5EkJyI0WUqJMk04HHjREl/9RTak8mo/eaqjUMTAOyweSwpaYRCddBOo
-y1ix9yH0fSBib1+WQ3MAHZHgbgVnu7V2GnB6qMNqRLHoGa03x+5Q1X0QuKxP6iYo
-9tiGt3k=
+A1UdJQQLMAkGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBAHGR7TUjyGt7IbqD
+MW/MfOkLtvpv1f3MhbRSmYDweGKejh2xQIONC/BlaBA2RWmhJIYTdc8wPRlcC76D
+2HLhBmGyOSy+ZTX/txGhtXm+xzNuhLF95VKDd2Z+06CMe1CptH1fvnf5YaZsUgv4
+nXmRN2i4WWrVHoWsAFCcEM6PqT9j/2485DbjtmoS7nVNvO0UKJs2vGgZYuxgYQsl
+S387YJnSbC3/VjTHGBh+R7oRZ0cBvpviWyp5Xak0kNcWAUSu3Oa1FRYDz6Cw/r7/
+wrTWxMA9W3Ygzeh+JFpYZkj5BNrwFem8UxrM/g2ZvXVS81dKGfA5spEZ/cEsAkU1
+8mWgcJY=
-----END CERTIFICATE-----
[exts_none]
EOF
-# Generate a private key.
+# Generate an RSA private key and a password-protected PEM file for it..
openssl genrsa $KEYSIZE > privkey.pem
openssl rsa -in privkey.pem -out privkey-enc.pem -des3 -passout pass:encrypted
+# Generate an EC private key.
+openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 > eckey.pem
+
# Generate a "CA" certificate.
SUBJECT=ca openssl req -config openssl.cnf -new -x509 -extensions exts_ca \
-set_serial 1 -days $DAYS -key privkey.pem -out ca.pem
serial=2
gen_cert() {
- SUBJECT=$1 openssl req -config openssl.cnf -new -key privkey.pem -out csr
+ keyfile=${4-privkey.pem}
+ SUBJECT=$1 openssl req -config openssl.cnf -new -key $keyfile -out csr
SUBJECT=$1 openssl x509 -extfile openssl.cnf -extensions $2 \
-set_serial $serial -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
-in csr -out $3
gen_pkcs12 user.pem user.p12
gen_pkcs12 user.pem user-enc.p12 encrypted
+# Generate an EC client certificate.
+gen_cert user exts_client ecuser.pem eckey.pem
+
# Generate a client certificate and PKCS#12 bundle with a UPN SAN.
gen_cert user exts_upn_client user-upn.pem
gen_pkcs12 user-upn.pem user-upn.p12
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,5FFF1E71BFFB65E3
-
-p89x5YEL+Mb6IPZXEkkr0KC4Wj+JtgE3VKdTT0wEcRD74QVv+dbbZt62WgmpJtId
-ph0Ial2z5Mws8L/aTkPdW2H/bEroApLu4TfUV+w67KcWgrc8gOg73d6gEObqx8li
-qGbs7FC1cI1WfDfnNOnCbD66e5+bTI8fDuchaieNRqzROd9RHhmlBHgylTmf55us
-laGuwLq2cZk/+Xz0M8PPx07uauGkAK0fyfifn/JR3PsGsE9s334osVQMjbjyT0VE
-rm8HGm3PvZHHDUnkOh7AGKyEtsIa5fJAULUjugp2lQJqOigC4HVn8a33xfLI0F1+
-2nH9MZ+Ap1rtI1cJX8CDn/Ij9oFt01scLxynYekYej11zFiR6qHC0sspxu0Yi8l0
-puBPXCI0GzyF9I53ukjGeibTtssz5yw1r+2oVasR4bvfXczPjqTQCBsPSUayNNhw
-RgT7k4QTY2OlrK/5XdILBzBlsvfndXgGOwEDw4YE7PMzMmz69vPMK7CfedUqtuXq
-bGBks58tzeOa4NSfVDOuFLI+LMkoYWMSjPGD/I0trX41xCU+O6PZOnDyt5ZWl1Tm
-klJpsB7rUcwsP8d4w4QGhyyV6Mo2MTlnTILr4CwwvmDMBch3yzwbfKdeywsFQh0S
-NMrG3aYNO7csRRTD6aGvYcBCbavWq7Ujsb/fV7SOIS26f4VEqewvOFlFEXm66zaz
-GJ0IcjtNHYNIIIW4690djxPqlGgbIZTblBSBlT+iOW5HrhXvrLeMmwAPxInU5dK+
-ypk2MGc4SzemkDi8H9jDW3dwbgcvVD9wn0glhVLQKWvP6F73UUdVEXMCZ+960xnR
-gxeEwDdIpzXNadWdON1kRbqI2KesRY/XQErGHDOvf2gNSM9V2gPz+5humvcu3mXY
-r4537On4+IdzetEVtI7D0slgojs+jN8waigpkLFB5RVl8PnzblMuWOkHNA86rrp+
-h6wNqv9kHLgPjpAyB1l/7w4VqXLXeC4PdaGc2fcpdNWOncUnHROmDmYvdTocqhIF
-bAsEFV7QZoTgDB7J6vLsmbtfawtHMSb81V/wTJWRrtY/gJCrkJXR2pTYAZlPX6vK
-aK7K2NuhJFMnrQD+kxsrloSEyfsZmHtk0mAVXJw4wSxlH3eGQ+Jphb/M2wtsnWV1
-w0fehxL2Vd5SyBBctAGhUirhRngbOO/E8IioymrziQ88vJZs2DxvbuNG4WKTuTwj
-CIggXohCNKdqrwL2HAynm2FVEWhbKrQwe4kjZc64WjccR4cy9vv+dxFfrKl+vZ1o
-Wvb0WXND7fiSBrPo7OfaYM5HjrcvIRP1AtMuArhuQYVARmawUG0l7dFLN97Rh9M+
-Ud9vBIfQYlubnTGVVm/5xrUh2isQbp2vrZLfMrUNXMQm0vSxKgGkAxqNUuklJC06
-LvCtEWMYXiBmB1zP4khwCHmHB+/E1gHBAutCzhpPu86ayEtNHBHIFkqKvZSg/UuZ
-+ygDdTJV00I2neIdeQcyG+vPg6huIDIHpG5u6eQn5sLqVkhr+apeNcskMWpdkpFS
-Lo62KUZDR3yB83ne63c3IGex0hWhVojJOAxykpGp6OD9uFn6Xn7x2Q==
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIBw7aG13XYxwCAggA
+MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPWyEPoKz4WhBIIEyKHdx+pkDxax
+dCCUZHsJ54boZxh+7f7xmO9Rjm+6+3cE+WCjPsiGHPUDtOXLxWwcrG0RAmA1GmrE
+yZbclwEMF8LcWQ3EUDMCJXBs7CEtA4XDH+EW1KsZwP+cA53ZFFikGj3sW6Ix5GLi
+Df311Eumhp3GABU57siNn+tMZJAorInth5lXBJFQoE3KJbBrSN9iQKZTOpgr4G3B
+G+qzBwrUKnZrGIp42t8op4VkB8sA6xoHh/huJB5pNygt9OZUQ+xdxvNQq+5/kJ2I
+mP/JRPSuN4GtnNA4fBB6tPv8t0L8hActkWlQ1rSJwWnWge3t4r5/3FBcAbl+zq3k
+t8A0LWgjsiQRmlKRN7GrzorOUKFv+7YAq6rc1Ek79qitUgEiFkwZZySt5+yPstMW
+vpaq2V0yDHf5Ds9uXffprhSAjnfXdT4NTg5eMeH65OEedUpVVzHauoGfFkDGaq8L
+8XgWPZPaz6GQFpU5SGk8FZn0OLLJHnHQDYo+ViL2XSuuqY8Jd7fmpzqVoHOU8k9Q
+/ONKW+E6uvkpNH6NbknceA/ip1bcdfwA/uRBckXjCc5uR0oB18M4UQPuKlcGev39
+mcdlvzQJxl2EWbB8ULazzuzOVfCAEwKc96qOkDAY94CB69f/KhBOd2QqHzdxrQ+3
++K+YduhbfP49Vxaq4NIklS/kSSv4GEBHzEwtFxX4oqN4Er+UkBSB423nvlkSLd1g
+tR4M30lJyzmHtOEpSOZYLakviz36ZOCV/DsxrfziNG/0RB/mPLm/B5L+StqjJrTY
+Pjo3QHKb+6ShhTi+jZ8tqXa68+TZO3Q7eTgqrcn8mq9jfama0KQF/13kmUsrFXTS
+wk/nbSP10z+MhO68z7o3j+Q0Co/cXkQke4slvc3DqLNvpQdDMPLKQVxtkPBq5czr
+dbk5K2GYFLNWO5Tv2RgBGomznoAGSolz5ozIqxffVHAK4NGfhihgLO/6GujDANVz
+EX/2/IacRg0L0x7//O/GHomiFvWYnDbHhRNicERe/ji1TCxJ5glqntFjOXDumwi6
+f+mQWNWlQWtKq0IOnlHrBB+vqykAj+e+FROqJjuNI6hu4CNnrBK3Hf+NY+rXdn7l
+iCTD3ojdufqo0JDZe8dXea+B7Zu7WNAxnpW8D018DJxR2hoBvT4Po1CBaHLfxAkT
+ZGeXMjp1vZ348xBSppFpIpYjFRQBeBgSezzA66o3YIcDeHu2bTzg73DiUXNgV3RG
+OyJHmsOmN9Gax/Cx4z6/Ff7seisXpIMRU9TDrRCFKAcPHXAl3R4L6guK0I5OGwz3
+GSMxsx3PGitj0x+1ynW/Tf+EJQD33ognc+kuQfNL0XW2tNJoibZIs1WgdbDwD9RD
+X7rbb9GfSJlQUnBFG/EKU7SGmFZUVMz7we8vckZ1PfeIKfH7OWrZ2i1WxIF2WO1K
+BX4TXp0KKt+aCwf1GInQ/6aYgh5g8W2iKuz2HJeZIN+ohciNmpOynsFmHGXdbvnO
+Kw+msZEQb5AvhXf4ToiSwZLSwq3qAILN8fOQQ9ta1DjJuUtITpe6ys9xhlnriUkm
+KrY50GkimLdD6XszC2uNulAuh3o0nZplqxC9IOLh+uasEU/+xqtwTaaYBljTpH2C
+8FPAEFFUVy6lsngJEQvdjw==
+-----END ENCRYPTED PRIVATE KEY-----
------BEGIN RSA PRIVATE KEY-----
-MIIEoAIBAAKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtr
-vmBIaYcnPq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE
-1/N4QMrzyKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOC
-ByG8F44YQTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiW
-gL0/iO25YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNH
-uShYa0PeyiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABAoIBAEpnKYMR0h6xyNjo
-VGIpT6BYB1UHPbVo0N9Ly6TCoIqpPe5DioDVyTye5A4OQlgu1G3ISqPme6478ApA
-ZZMw7/42QgdlknnOzbKaAWkZK02Sa8RP9hrXL8CvuDisOjzXCHd7RdXevzSmPfsS
-5sgdK3YFnKqMPwbCcKf61CHXvHJjWGuTIHIRh8P7gJelA4ahO0kYQ8aRXv3ldquO
-ukSI5gyk9CN+aAHqt25kEmt9oOgk+8kfKpnk+5gkOCY2YOFDDckD7nL1VIIrDxwG
-SmU598qjVwycDairWUY8uSuPCOLgbvDM9N8cERDMsyNQL63GE8ZZyHZsJ3Pbwdfs
-JVHh5ekCgYEA/CwhaT9D0WQ49GQdeI7aqazHEYDmqPdE2/qbmr67tPMZzX8AAk9j
-r4aMT+oIdtIMPdoQNNcBP6NYZLlAoMbLoAzHmWJnF5/YWLnS2Wg9OuXUOBn3jk1l
-SWelJfAKGeBld5fpSLTdHjRAwJrNCX+mc0IZIiEw2IvGUPgKGX08bX8CgYEA0swx
-xCDgvfoaKueInw/rUIcKxrSxK3pDhaR01Dg2pwSo7Vj9W01zf33qe+mjma6+U2SB
-fk+/O2VXDuEOmVDLwvp6PkmUeRE5PyH7urTMEjy5ELNGiZd9zHoG/zJnRgPwTjuW
-yguvjVGJwI1IvmODuA7Xc7iHFlvGNuxXZjPkS2UCgYA0nFxoIdvbTsaXLl/7rAow
-xixOGY+GBvil0HYwZcSxrtpeRjXRRZDtqOuTLKeRaqdFLD6fV5AaH9EsSn4STQdk
-n+XwuVf61M2FTVeRJi9IH3UUM06zsLAGDYqmDJt+5JMmzVnNYnaTe6FazbEjXy9x
-8oNd3IDdXOQGNomc4cT+rwKBgBbABOr25Wp7cJGK1XrdO/c/69DQNYLMujbVLeqt
-enCCFz0uaoGNFVcAHutqpsZyToYvha49KxVc9Y1cirfPOX58i+7nAAgk7Lm8kC9x
-Tcj2Fr8PqiA1YlVMIi8uoGi1Ch1XXwnFQxgMYcKPPPeXQ+L8bxJFKwcltnm8/h3A
-ofXlAn9AW6fYZLSzOfNQTMnuukhuAtZcEW9NlJHbej305zK89J66S8wroQs5iOla
-5GG+S4YaZh5sVGw+mnS+FCw7cQCUk40kXwX3yTrxlX1qGSCFCQnFdJow+5NVg4D+
-dzDKzniH71OZZFxTqiiz76XxiaW/rS1uOfP/WSVR9NBLpV5n
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCb/Um3NkEmx1p2
+Y5OeSX3jnTxlLJijnE/zewtP9JjkKuLVApoWu57aQaCCXVAQ4TEGsht0B67kF+2q
+ILTsfIaC6C1GjSoMcxGdDi2w0THNjPr0w6QUTiExiNSj70LbYZUuKHKir6gQs3uu
+jfS7n8wI7utQsinQd6QspD64A1VUnH7GdbdswmytEhdnH2QHSMgi6Bi3kPefzS90
+iMdAl/YFOOwFZgZEkPixMSUYW1EiIPqbim6idF1SC0dQdns4IpNjmxTQ9IbEVEuL
+/KSpyA89B10dgJ3kxEmPmrY2883pRgNsx/OqeLS4ND2p0OMePoKZEIc0q+Qpot0F
++F2oUq5lAgMBAAECggEADwzB9vY6FPa46KE01dm7VqGN+SjzVR24rQIbFkzAD4t/
+tRN6MGVLrz0TsmA0YFyJsV6vvWMcYY9Zc8eSDRr6k1i5PYxTGT5k3aVHjT6xsmY+
+tCzIANmE5FWSRnrIFYh1ry1h2gZejbXzYeT6TrvdIKOEepWl6SIR6eiy0Ggp7G7C
+SjlpT96ZtdE2RnlvcxcACtwhe3vPbkLmTCOEqeZ6LHCHIHiK4KdJgJ08OjU7Kgsr
++vmnwTJsH5s0b5IIznfWajO4JNOpqjzFDjDctGYBwp5xF4zu3u4bKe9aleM0q/jl
+ZkibxLsFAh3Xkh89nxr3E6oBLm0F8r8M7PK5wpMShQKBgQDAipf6T6XUY+ugkKw+
+301LyoAch6WV9oT6uOJsAttmcUpUr6NXhRT3OM4oqyYsAc5JW2wbz+n6lED3j6Ez
+QEKSIFrYpjrYr9D7hqvISI9JT0PhVSPXECfifEyIR9xmLvV9WQq7NRCJMi26X9ab
+Grqpw1HNlPA/rdcc/dY0p25DlwKBgQDPZqxSnwnTa6X+r0UdR8l6kc9VuESotpbE
+0ziF222bpXmZ2GKiEU1buFORHih/e3yDvKvq+p2apyUKnEEVQg/TL8/Jzya7fEOI
+lTXcNQ/f78ef+nwEAxdRVQkWXFWHvvKUHm1rGCIY7zeOLnQ9JjBQkgG8zhUamAP1
+owLBBTstYwKBgQC+yNX9Du0HvpbdfF1g0025OwekvXiDV0m/UnHxiwcxxDJeJceZ
+0mHK8nu9apGha4ynvbIrAOMdC8gwRh76NMOCHhNGt7h5vAU9Jt2S0OtCPgvJ/N5N
+nVGYJ4iCRYqLqh5QvWlXxSYEfDc5hPuWp26tBsBJEDrbLnuH27JkbD9jMwKBgQCM
+f1VFMw+I9WehvEHpr/PA4H2/5/A7ClXgR+YGZ7s8sUBLA9btSyNIevnBWNi+Y3za
+ETm1GMkjNw9UvL0qFXJ68eylHXtzjp6BK/MslZWHcfudWCYi4aUuJ5jcWPhn2Oaj
+iGk/Hz4Z/hN4cee0dOZN7lrW+BQ7y7cC88at00lfWQKBgQC7YeW02aUPw9jMJh1x
+lDfBh+E5sdRwRQIvh3BuyTd+m/LI+3b9RSy+LIL2KFJucwKm9zR9fy33tHF2S5En
+Q+inhyXfOEygal5Rzxe3Pfx+pGZbzr6IXkhquHtjuFBwJJCrSeR66V2xDmzJfCj4
+TY+CzwOJ/EltH4ZjPwEmE0S7+w==
+-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+MIIExTCCA62gAwIBAgIBBTANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMVoXDTMyMDkyMDIxMTEzMVowSjELMAkG
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSjELMAkG
A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtrvmBIaYcn
-Pq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE1/N4QMrz
-yKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOCByG8F44Y
-QTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiWgL0/iO25
-YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNHuShYa0Pe
-yiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFPQX
-pfvVBF+0OJJ41JjduSzecrQjMIHUBgNVHSMEgcwwgcmAFPQXpfvVBF+0OJJ41Jjd
-uSzecrQjoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+CgKCAQEAm/1JtzZBJsdadmOTnkl94508ZSyYo5xP83sLT/SY5Cri1QKaFrue2kGg
+gl1QEOExBrIbdAeu5BftqiC07HyGgugtRo0qDHMRnQ4tsNExzYz69MOkFE4hMYjU
+o+9C22GVLihyoq+oELN7ro30u5/MCO7rULIp0HekLKQ+uANVVJx+xnW3bMJsrRIX
+Zx9kB0jIIugYt5D3n80vdIjHQJf2BTjsBWYGRJD4sTElGFtRIiD6m4puonRdUgtH
+UHZ7OCKTY5sU0PSGxFRLi/ykqcgPPQddHYCd5MRJj5q2NvPN6UYDbMfzqni0uDQ9
+qdDjHj6CmRCHNKvkKaLdBfhdqFKuZQIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFJI/
++nOV5fnNVxn2GkjkYbZ5D6mqMIHUBgNVHSMEgcwwgcmAFJI/+nOV5fnNVxn2Gkjk
+YbZ5D6mqoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
BAQDAgPoMAwGA1UdEwEB/wQCMAAwKwYDVR0RBCQwIqAgBgorBgEEAYI3FAIDoBIM
EHVzZXJAa3JidGVzdC5jb20wEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0B
-AQsFAAOCAQEAYTW8tzURX2s8vuDawXEJt2as5q2MnvhUmG0YPIvK4n2fODkMW/I9
-XENFhK8wwQJNdzvBUwXUXzEGjFcGPs672ZVzykRb7sAfGlNu1f15z0KrjyUj82oz
-/gWoLwdYwZnO8jqtKjGtnLi2MeWjVCoiUW5ypUGwtEdcyZUG0PeRUrdrZu5cm+iZ
-1B1exR4lepR1iSAPYTNhp5VF6T8BSLf2BO2IKTgFnF4Xx1vyZZTsY10mruZ8S1ZR
-XiajBVdHkN1BpWWyFKt1BCt0dpRx9W7CihC3Ln9fBCsY8QA969EjRhszG2i09Xxw
-0M6/UgIQRU6hy7QTlcmehDKY0zvVJ2/RLw==
+AQsFAAOCAQEAbe5/xDlFplE/h6BSqXSftjyiPgRlmPPkuTwiKHfmHYHv+KXHBDFY
+wuGDu4Tdh/qisskXJGoKYfRsOox6AW3ZTcklkjvVw0V73nPo+98USWYTzKq7NriF
+rJ9skYALu/Yv6q8iEoziOyDG55LppWne5KH0Of5ctikZVthxDnjm/saSR1lNa+8A
+gB6x9uid73qw+seg1/DoOdb+uHGnKBeSUrJC9vtdfodYdeatNFDDNoxqjGPajDNT
+TGI2ace2yZAgD/ic1MzI/s2eTHfzzO+puJIPzLScdy80RYMeILQs9g+x5NhOUuMz
+YMVFE0PAQLshVggtJ9l8fmHmrrJXP9BAWw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEuTCCA6GgAwIBAgIBBTANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+MIIEuTCCA6GgAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMVoXDTMyMDkyMDIxMTEzMVowSjELMAkG
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSjELMAkG
A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtrvmBIaYcn
-Pq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE1/N4QMrz
-yKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOCByG8F44Y
-QTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiWgL0/iO25
-YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNHuShYa0Pe
-yiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABo4IBSjCCAUYwHQYDVR0OBBYEFPQX
-pfvVBF+0OJJ41JjduSzecrQjMIHUBgNVHSMEgcwwgcmAFPQXpfvVBF+0OJJ41Jjd
-uSzecrQjoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+CgKCAQEAm/1JtzZBJsdadmOTnkl94508ZSyYo5xP83sLT/SY5Cri1QKaFrue2kGg
+gl1QEOExBrIbdAeu5BftqiC07HyGgugtRo0qDHMRnQ4tsNExzYz69MOkFE4hMYjU
+o+9C22GVLihyoq+oELN7ro30u5/MCO7rULIp0HekLKQ+uANVVJx+xnW3bMJsrRIX
+Zx9kB0jIIugYt5D3n80vdIjHQJf2BTjsBWYGRJD4sTElGFtRIiD6m4puonRdUgtH
+UHZ7OCKTY5sU0PSGxFRLi/ykqcgPPQddHYCd5MRJj5q2NvPN6UYDbMfzqni0uDQ9
+qdDjHj6CmRCHNKvkKaLdBfhdqFKuZQIDAQABo4IBSjCCAUYwHQYDVR0OBBYEFJI/
++nOV5fnNVxn2GkjkYbZ5D6mqMIHUBgNVHSMEgcwwgcmAFJI/+nOV5fnNVxn2Gkjk
+YbZ5D6mqoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
BAQDAgPoMAwGA1UdEwEB/wQCMAAwHwYDVR0RBBgwFqAUBgorBgEEAYI3FAIDoAYM
-BHVzZXIwEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0BAQsFAAOCAQEAAsGC
-LvikD/nW3eOym4f/uuKBscOGSByP9/HoP8QwvnLYU00i5n+zXSTQctotHIifsRc4
-xHLO8xemJp7rm0h/27C1Wo5AVxJ0cmnDKQf8Ast+QXsz9ZeaeKLa5D8sDOfnZXJB
-aMTb8ChjyZz+KLjXV0VbaVkY95mfqsOoJQcl9wHhNdDOygnSucvA5Svlrbo2rlKt
-75OJZJJWrZxuaBuuSYNpCKyyg61t69hPoDKDQZ8QJZHGugWqQ2swYe9dZpUYy5xV
-CGTLCAk9ZOn8hTCC6xbNaJFjflIjcjpwabw0r986/9GeAF6KqSNbMXKaY4LLuk/8
-5FH9S8/3F56ZCNxbZQ==
+BHVzZXIwEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0BAQsFAAOCAQEAFN2R
+gVMM5HNoXuwBPcpNsP5AVSoQRTAv6UUxAjTPLGH5mE6LGW8/JxM0R5x0PdVyU3u7
+zq4qa10XdGJpSt94cD6m7R61Sw6ru9PBtHmB0oUfkWRa2+SJpjmcwyc86W0XRBhr
+OhD0QGOnF1hGyTYzPViGxRZFVMiqXsWuAJ4i6uTyyPeeN+UuehQ3SsVEA1csrKMy
+dNT7FKQBvUTBnSZ9rxphGBrw/NZQyG74KxG5W3Nsnq89VK6+ESJcsUOT55WrHRwE
+CwKoeX+otyj8ptOwKaaje0DZnSXTXqEag4G4PgH4ovd+ehad0JaE4jtQTm+Vy15W
+cwHSMGSA+Kq1Hsqhhw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+MIIExTCCA62gAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMVoXDTMyMDkyMDIxMTEzMVowSjELMAkG
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSjELMAkG
A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtrvmBIaYcn
-Pq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE1/N4QMrz
-yKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOCByG8F44Y
-QTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiWgL0/iO25
-YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNHuShYa0Pe
-yiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFPQX
-pfvVBF+0OJJ41JjduSzecrQjMIHUBgNVHSMEgcwwgcmAFPQXpfvVBF+0OJJ41Jjd
-uSzecrQjoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+CgKCAQEAm/1JtzZBJsdadmOTnkl94508ZSyYo5xP83sLT/SY5Cri1QKaFrue2kGg
+gl1QEOExBrIbdAeu5BftqiC07HyGgugtRo0qDHMRnQ4tsNExzYz69MOkFE4hMYjU
+o+9C22GVLihyoq+oELN7ro30u5/MCO7rULIp0HekLKQ+uANVVJx+xnW3bMJsrRIX
+Zx9kB0jIIugYt5D3n80vdIjHQJf2BTjsBWYGRJD4sTElGFtRIiD6m4puonRdUgtH
+UHZ7OCKTY5sU0PSGxFRLi/ykqcgPPQddHYCd5MRJj5q2NvPN6UYDbMfzqni0uDQ9
+qdDjHj6CmRCHNKvkKaLdBfhdqFKuZQIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFJI/
++nOV5fnNVxn2GkjkYbZ5D6mqMIHUBgNVHSMEgcwwgcmAFJI/+nOV5fnNVxn2Gkjk
+YbZ5D6mqoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
BAQDAgPoMAwGA1UdEwEB/wQCMAAwKwYDVR0RBCQwIqAgBgorBgEEAYI3FAIDoBIM
EHVzZXJAS1JCVEVTVC5DT00wEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0B
-AQsFAAOCAQEApwXjFJ86RLM4MzbScqk0JGqm+jzaFZ6h5oyt0rlaxdhOl7kqOmIE
-sLhXtvZm75roA+UULZHumB6xg3Y0p7cc6VBAYYycWoNkhWXZMdQ8Q33vMos5cwLY
-kXjl4oTDK53goh8IlriRMV7Tv/QpJ8wh+7iqQn3lak0Tv51JexYGwp5sJREYm8q5
-rr3ChlgH7SWF8mhbu2EEiipm0whEqA4tlNKGBsTQBslnm8sK0VfVDcmLOGbMNjRs
-r+Hkd8yVvhIJ9M+WAp/OeF2vUzPBJtAfIaJBxcZmKtNI5Jk8cK/vScJZboa0qAAz
-2Y1uC9rP830mpOe0juhV2mMPron0hi1HaA==
+AQsFAAOCAQEASLN4+MiZUQwBzQ3ezt1B8Zx8jHL7a16s1H5v1J2Dwne/pM/risjg
+ZAlv65IlKEp2E6cqcmCPajlZ967vJr1qC+OSV2AZuL8HZlg+ISacoII9T97X9/UJ
+AJfOWBN6y0DQ7s6OLSunf0+mAw+LKmFoIQeO5+DvU4chEYkcs6NbbAos/He1Wgq/
+RTz9J3EhGuoDVgqq/avrTsgW9HyrHsG+Y/6n4cX2lq+VV7h8fG91hC073Rz9QMFY
+q/pBqFqIE/FrgA4YbpOrSx6m+eOyFSAWTLtmlJmROiNYo4ZuGmBtrDntet+YK75A
+8Rsfbapjn4SKJzgJseVgUbEEMOFcugQBfQ==
-----END CERTIFICATE-----
FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTIxMTAwODIxMTEzMFoXDTMyMDkyMDIxMTEzMFowSjELMAkG
+b3RoZXJ3aXNlMB4XDTI0MDIxNTA0NTkwN1oXDTM1MDEyODA0NTkwN1owSjELMAkG
A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAz6VXmJpVq2zTIEU3gUF7pui+Wg17d3QX2oy6EqqUQK/pwWtrvmBIaYcn
-Pq0ZMrzMhNTuyeLjb1rNNkL0hCdS3/aVbx1bOlkPVPlW3UNi9gWpXOOE1/N4QMrz
-yKAQ1/Npf9xjY/vpqsmvRx7AZpq7Nq7HyF5hbUKMHFaaTqRarhoP7mOCByG8F44Y
-QTY2RXcw9te63x+77c3O64gbtnSKXBC/4pS9DxBBv1ULB2wOH8RGxDiWgL0/iO25
-YImKQgTvwbENw4ygLV+0m1b+YEJLaIIeKleunYEMMkzIfFmMemXRWgNHuShYa0Pe
-yiwTBSRdW9Yi4qzjfaHZ1dD67wdoGwIDAQABo4IBZDCCAWAwHQYDVR0OBBYEFPQX
-pfvVBF+0OJJ41JjduSzecrQjMIHUBgNVHSMEgcwwgcmAFPQXpfvVBF+0OJJ41Jjd
-uSzecrQjoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+CgKCAQEAm/1JtzZBJsdadmOTnkl94508ZSyYo5xP83sLT/SY5Cri1QKaFrue2kGg
+gl1QEOExBrIbdAeu5BftqiC07HyGgugtRo0qDHMRnQ4tsNExzYz69MOkFE4hMYjU
+o+9C22GVLihyoq+oELN7ro30u5/MCO7rULIp0HekLKQ+uANVVJx+xnW3bMJsrRIX
+Zx9kB0jIIugYt5D3n80vdIjHQJf2BTjsBWYGRJD4sTElGFtRIiD6m4puonRdUgtH
+UHZ7OCKTY5sU0PSGxFRLi/ykqcgPPQddHYCd5MRJj5q2NvPN6UYDbMfzqni0uDQ9
+qdDjHj6CmRCHNKvkKaLdBfhdqFKuZQIDAQABo4IBZDCCAWAwHQYDVR0OBBYEFJI/
++nOV5fnNVxn2GkjkYbZ5D6mqMIHUBgNVHSMEgcwwgcmAFJI/+nOV5fnNVxn2Gkjk
+YbZ5D6mqoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
BAQDAgPoMAwGA1UdEwEB/wQCMAAwOQYDVR0RBDIwMKAuBgYrBgEFAgKgJDAioA0b
C0tSQlRFU1QuQ09NoREwD6ADAgEBoQgwBhsEdXNlcjASBgNVHSUECzAJBgcrBgEF
-AgMEMA0GCSqGSIb3DQEBCwUAA4IBAQAOBeCDK6Eg6Cu8TZ7xeAw2AbTpaW04nNSV
-Fmm0aIskMgLl2a5KEmalG7rnArRXv5IZVYFjJ6X0MzjOx+BgaGUCvN8jz1fuO3Hp
-iGhxPDzKjFMWJeY/z5bQRueSI6RCC8DzH8iPdlPUQ8ZhnukhY1Vt47wqraf197uT
-0XP21qQr1uRY+ZcLSBKZuKe9ZP3ijh57MOLvYDdAFxVp77JLznpk+oU18ujAtYgZ
-7naIGYtSQRkIi970jk82hSpc9B/KN8UcDuo+DQHWPQaDf39s30qoxooZBoue5ipp
-LQHuVaX5Hoi83cWbsVluce/JsW8GfbuC8+8CosAmzJly183f8++9
+AgMEMA0GCSqGSIb3DQEBCwUAA4IBAQBRWsxPb9miF9xf8rEIfVko0qBy8doEJsPE
+IVD9Jz/Ml/TBZRLbi1b94l15Fto/Z6XKf8jrnBs4krf6tU2D5PUZXZYZ6tr/2kkY
+IpmoOkEoQX8gtcZfaq2OJzsKHnAJT159EVydyYahHU66i4aNvho74oAafrVTyk8B
+PHCHFs0MUct8DoNwrbnfH0cjqEdVOmjjvBN0yA+RxOa543XnQqkSmCuIJKoD6pUa
+07rE372iERgIjDnzCogiEo9cCBBqDfgsbr0ah1QbWJTJvnsFuxT43tBNurRjNPoX
+Jj6xAzhQLCuvqtKtWlAUOHut18YbVGXVT+3tm7+C6iA44JvMl9m1
-----END CERTIFICATE-----
# Construct a krb5.conf fragment configuring pkinit.
user_pem = os.path.join(pkinit_certs, 'user.pem')
+ecuser_pem = os.path.join(pkinit_certs, 'ecuser.pem')
privkey_pem = os.path.join(pkinit_certs, 'privkey.pem')
privkey_enc_pem = os.path.join(pkinit_certs, 'privkey-enc.pem')
+privkey_ec_pem = os.path.join(pkinit_certs, 'eckey.pem')
user_p12 = os.path.join(pkinit_certs, 'user.p12')
user_enc_p12 = os.path.join(pkinit_certs, 'user-enc.p12')
user_upn_p12 = os.path.join(pkinit_certs, 'user-upn.p12')
file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem)
file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem)
+ec_identity = 'FILE:%s,%s' % (ecuser_pem, privkey_ec_pem)
dir_identity = 'DIR:%s' % path
dir_enc_identity = 'DIR:%s' % path_enc
dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'),
realm.pkinit(realm.user_princ, expected_trace=('PKINIT using ' + g,),
env=group_env)
+# Test with an EC client cert.
+mark('EC client cert')
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % ec_identity])
+
# Try using multiple configured pkinit_identities, to make sure we
# fall back to the second one when the first one cannot be read.
id_conf = {'realms': {'$realm': {'pkinit_identities': [file_identity + 'X',
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
+mark('PKCS11 identity, EC client cert')
+shutil.rmtree(softhsm2_tokens)
+os.mkdir(softhsm2_tokens)
+realm.run(tool_cmd + ['--init-token', '--label', 'user',
+ '--so-pin', 'sopin', '--init-pin', '--pin', 'userpin'])
+realm.run(tool_cmd + ['-w', ecuser_pem, '-y', 'cert'])
+realm.run(tool_cmd + ['-w', privkey_ec_pem, '-y', 'privkey',
+ '-l', '--pin', 'userpin'])
+realm.kinit(realm.user_princ, flags=['-X', p11_attr], password='userpin')
+realm.klist(realm.user_princ)
+realm.run([kvno, realm.host_princ])
+
success('PKINIT tests')