From 5385de0f811d2854fdc47b26f87e377bb3151d16 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 28 2020 09:39:01 +0000 Subject: import krb5-1.17-18.el8 --- diff --git a/SOURCES/Add-function-and-enctype-flag-for-deprecations.patch b/SOURCES/Add-function-and-enctype-flag-for-deprecations.patch index 99290da..2a094e7 100644 --- a/SOURCES/Add-function-and-enctype-flag-for-deprecations.patch +++ b/SOURCES/Add-function-and-enctype-flag-for-deprecations.patch @@ -1,4 +1,4 @@ -From 656fb920da2d6be3c55976320e3e13a69af30c8a Mon Sep 17 00:00:00 2001 +From ba1fd0a44c74089d42af244ff2b315baf506fd2f Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Tue, 15 Jan 2019 16:16:57 -0500 Subject: [PATCH] Add function and enctype flag for deprecations diff --git a/SOURCES/Add-soft-pkcs11-source-code.patch b/SOURCES/Add-soft-pkcs11-source-code.patch new file mode 100644 index 0000000..25488b5 --- /dev/null +++ b/SOURCES/Add-soft-pkcs11-source-code.patch @@ -0,0 +1,2072 @@ +From c4626f17ece51265eaa5446e96104b115ecbe31c Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 20 Jun 2019 10:45:18 -0400 +Subject: [PATCH] Add soft-pkcs11 source code + +soft-pkcs11 is no longer available upstream and is not generally +packaged in distributions, making it inconvenient to use for tests. +Import the 1.8 source code, detabified and with trailing whitespace +removed but otherwise unmodified. + +(cherry picked from commit a4bc3e513a58b0d1292f3506ac3b35be8c178086) +(cherry picked from commit a186597238ae40e167ce041857b5bd1f94ee2383) +--- + src/tests/softpkcs11/main.c | 2049 +++++++++++++++++++++++++++++++++++ + 1 file changed, 2049 insertions(+) + create mode 100644 src/tests/softpkcs11/main.c + +diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c +new file mode 100644 +index 000000000..2acec5169 +--- /dev/null ++++ b/src/tests/softpkcs11/main.c +@@ -0,0 +1,2049 @@ ++/* ++ * Copyright (c) 2004-2006, Stockholms universitet ++ * (Stockholm University, Stockholm Sweden) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. Neither the name of the university nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "locl.h" ++ ++/* RCSID("$Id: main.c,v 1.24 2006/01/11 12:42:53 lha Exp $"); */ ++ ++#define OBJECT_ID_MASK 0xfff ++#define HANDLE_OBJECT_ID(h) ((h) & OBJECT_ID_MASK) ++#define OBJECT_ID(obj) HANDLE_OBJECT_ID((obj)->object_handle) ++ ++struct st_attr { ++ CK_ATTRIBUTE attribute; ++ int secret; ++}; ++ ++struct st_object { ++ CK_OBJECT_HANDLE object_handle; ++ struct st_attr *attrs; ++ int num_attributes; ++ enum { ++ STO_T_CERTIFICATE, ++ STO_T_PRIVATE_KEY, ++ STO_T_PUBLIC_KEY ++ } type; ++ union { ++ X509 *cert; ++ EVP_PKEY *public_key; ++ struct { ++ const char *file; ++ EVP_PKEY *key; ++ X509 *cert; ++ } private_key; ++ } u; ++}; ++ ++static struct soft_token { ++ CK_VOID_PTR application; ++ CK_NOTIFY notify; ++ struct { ++ struct st_object **objs; ++ int num_objs; ++ } object; ++ struct { ++ int hardware_slot; ++ int app_error_fatal; ++ int login_done; ++ } flags; ++ int open_sessions; ++ struct session_state { ++ CK_SESSION_HANDLE session_handle; ++ ++ struct { ++ CK_ATTRIBUTE *attributes; ++ CK_ULONG num_attributes; ++ int next_object; ++ } find; ++ ++ int encrypt_object; ++ CK_MECHANISM_PTR encrypt_mechanism; ++ int decrypt_object; ++ CK_MECHANISM_PTR decrypt_mechanism; ++ int sign_object; ++ CK_MECHANISM_PTR sign_mechanism; ++ int verify_object; ++ CK_MECHANISM_PTR verify_mechanism; ++ int digest_object; ++ } state[10]; ++#define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0])) ++ FILE *logfile; ++} soft_token; ++ ++static void ++application_error(const char *fmt, ...) ++{ ++ va_list ap; ++ va_start(ap, fmt); ++ vprintf(fmt, ap); ++ va_end(ap); ++ if (soft_token.flags.app_error_fatal) ++ abort(); ++} ++ ++static void ++st_logf(const char *fmt, ...) ++{ ++ va_list ap; ++ if (soft_token.logfile == NULL) ++ return; ++ va_start(ap, fmt); ++ vfprintf(soft_token.logfile, fmt, ap); ++ va_end(ap); ++ fflush(soft_token.logfile); ++} ++ ++static void ++snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...) ++{ ++ int len; ++ va_list ap; ++ len = vsnprintf(str, size, fmt, ap); ++ va_end(ap); ++ if (len < 0 || len > size) ++ return; ++ while(len < size) ++ str[len++] = fillchar; ++} ++ ++#ifndef TEST_APP ++#define printf error_use_st_logf ++#endif ++ ++#define VERIFY_SESSION_HANDLE(s, state) \ ++{ \ ++ CK_RV ret; \ ++ ret = verify_session_handle(s, state); \ ++ if (ret != CKR_OK) { \ ++ /* return CKR_OK */; \ ++ } \ ++} ++ ++static CK_RV ++verify_session_handle(CK_SESSION_HANDLE hSession, ++ struct session_state **state) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_NUM_SESSION; i++){ ++ if (soft_token.state[i].session_handle == hSession) ++ break; ++ } ++ if (i == MAX_NUM_SESSION) { ++ application_error("use of invalid handle: 0x%08lx\n", ++ (unsigned long)hSession); ++ return CKR_SESSION_HANDLE_INVALID; ++ } ++ if (state) ++ *state = &soft_token.state[i]; ++ return CKR_OK; ++} ++ ++static CK_RV ++object_handle_to_object(CK_OBJECT_HANDLE handle, ++ struct st_object **object) ++{ ++ int i = HANDLE_OBJECT_ID(handle); ++ ++ *object = NULL; ++ if (i >= soft_token.object.num_objs) ++ return CKR_ARGUMENTS_BAD; ++ if (soft_token.object.objs[i] == NULL) ++ return CKR_ARGUMENTS_BAD; ++ if (soft_token.object.objs[i]->object_handle != handle) ++ return CKR_ARGUMENTS_BAD; ++ *object = soft_token.object.objs[i]; ++ return CKR_OK; ++} ++ ++static int ++attributes_match(const struct st_object *obj, ++ const CK_ATTRIBUTE *attributes, ++ CK_ULONG num_attributes) ++{ ++ CK_ULONG i; ++ int j; ++ st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj)); ++ ++ for (i = 0; i < num_attributes; i++) { ++ int match = 0; ++ for (j = 0; j < obj->num_attributes; j++) { ++ if (attributes[i].type == obj->attrs[j].attribute.type && ++ attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen && ++ memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue, ++ attributes[i].ulValueLen) == 0) { ++ match = 1; ++ break; ++ } ++ } ++ if (match == 0) { ++ st_logf("type %d attribute have no match\n", attributes[i].type); ++ return 0; ++ } ++ } ++ st_logf("attribute matches\n"); ++ return 1; ++} ++ ++static void ++print_attributes(const CK_ATTRIBUTE *attributes, ++ CK_ULONG num_attributes) ++{ ++ CK_ULONG i; ++ ++ st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes); ++ ++ for (i = 0; i < num_attributes; i++) { ++ st_logf(" type: "); ++ switch (attributes[i].type) { ++ case CKA_TOKEN: { ++ CK_BBOOL *ck_true; ++ if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) { ++ application_error("token attribute wrong length\n"); ++ break; ++ } ++ ck_true = attributes[i].pValue; ++ st_logf("token: %s", *ck_true ? "TRUE" : "FALSE"); ++ break; ++ } ++ case CKA_CLASS: { ++ CK_OBJECT_CLASS *class; ++ if (attributes[i].ulValueLen != sizeof(CK_ULONG)) { ++ application_error("class attribute wrong length\n"); ++ break; ++ } ++ class = attributes[i].pValue; ++ st_logf("class "); ++ switch (*class) { ++ case CKO_CERTIFICATE: ++ st_logf("certificate"); ++ break; ++ case CKO_PUBLIC_KEY: ++ st_logf("public key"); ++ break; ++ case CKO_PRIVATE_KEY: ++ st_logf("private key"); ++ break; ++ case CKO_SECRET_KEY: ++ st_logf("secret key"); ++ break; ++ case CKO_DOMAIN_PARAMETERS: ++ st_logf("domain parameters"); ++ break; ++ default: ++ st_logf("[class %lx]", (long unsigned)*class); ++ break; ++ } ++ break; ++ } ++ case CKA_PRIVATE: ++ st_logf("private"); ++ break; ++ case CKA_LABEL: ++ st_logf("label"); ++ break; ++ case CKA_APPLICATION: ++ st_logf("application"); ++ break; ++ case CKA_VALUE: ++ st_logf("value"); ++ break; ++ case CKA_ID: ++ st_logf("id"); ++ break; ++ default: ++ st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type); ++ break; ++ } ++ st_logf("\n"); ++ } ++} ++ ++static struct st_object * ++add_st_object(void) ++{ ++ struct st_object *o, **objs; ++ int i; ++ ++ o = malloc(sizeof(*o)); ++ if (o == NULL) ++ return NULL; ++ memset(o, 0, sizeof(*o)); ++ o->attrs = NULL; ++ o->num_attributes = 0; ++ ++ for (i = 0; i < soft_token.object.num_objs; i++) { ++ if (soft_token.object.objs == NULL) { ++ soft_token.object.objs[i] = o; ++ break; ++ } ++ } ++ if (i == soft_token.object.num_objs) { ++ objs = realloc(soft_token.object.objs, ++ (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0])); ++ if (objs == NULL) { ++ free(o); ++ return NULL; ++ } ++ soft_token.object.objs = objs; ++ soft_token.object.objs[soft_token.object.num_objs++] = o; ++ } ++ soft_token.object.objs[i]->object_handle = ++ (random() & (~OBJECT_ID_MASK)) | i; ++ ++ return o; ++} ++ ++static CK_RV ++add_object_attribute(struct st_object *o, ++ int secret, ++ CK_ATTRIBUTE_TYPE type, ++ CK_VOID_PTR pValue, ++ CK_ULONG ulValueLen) ++{ ++ struct st_attr *a; ++ int i; ++ ++ i = o->num_attributes; ++ a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0])); ++ if (a == NULL) ++ return CKR_DEVICE_MEMORY; ++ o->attrs = a; ++ o->attrs[i].secret = secret; ++ o->attrs[i].attribute.type = type; ++ o->attrs[i].attribute.pValue = malloc(ulValueLen); ++ if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0) ++ return CKR_DEVICE_MEMORY; ++ memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen); ++ o->attrs[i].attribute.ulValueLen = ulValueLen; ++ o->num_attributes++; ++ ++ return CKR_OK; ++} ++ ++static CK_RV ++add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key) ++{ ++ switch (key_type) { ++ case CKK_RSA: { ++ CK_BYTE *modulus = NULL; ++ size_t modulus_len = 0; ++ CK_ULONG modulus_bits = 0; ++ CK_BYTE *exponent = NULL; ++ size_t exponent_len = 0; ++ ++ modulus_bits = BN_num_bits(key->pkey.rsa->n); ++ ++ modulus_len = BN_num_bytes(key->pkey.rsa->n); ++ modulus = malloc(modulus_len); ++ BN_bn2bin(key->pkey.rsa->n, modulus); ++ ++ exponent_len = BN_num_bytes(key->pkey.rsa->e); ++ exponent = malloc(exponent_len); ++ BN_bn2bin(key->pkey.rsa->e, exponent); ++ ++ add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len); ++ add_object_attribute(o, 0, CKA_MODULUS_BITS, ++ &modulus_bits, sizeof(modulus_bits)); ++ add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT, ++ exponent, exponent_len); ++ ++ RSA_set_method(key->pkey.rsa, RSA_PKCS1_SSLeay()); ++ ++ free(modulus); ++ free(exponent); ++ } ++ default: ++ /* XXX */ ++ break; ++ } ++ return CKR_OK; ++} ++ ++ ++static int ++pem_callback(char *buf, int num, int w, void *key) ++{ ++ return -1; ++} ++ ++ ++static CK_RV ++add_certificate(char *label, ++ const char *cert_file, ++ const char *private_key_file, ++ char *id, ++ int anchor) ++{ ++ struct st_object *o = NULL; ++ CK_BBOOL bool_true = CK_TRUE; ++ CK_BBOOL bool_false = CK_FALSE; ++ CK_OBJECT_CLASS c; ++ CK_CERTIFICATE_TYPE cert_type = CKC_X_509; ++ CK_KEY_TYPE key_type; ++ CK_MECHANISM_TYPE mech_type; ++ void *cert_data = NULL; ++ size_t cert_length; ++ void *subject_data = NULL; ++ size_t subject_length; ++ void *issuer_data = NULL; ++ size_t issuer_length; ++ void *serial_data = NULL; ++ size_t serial_length; ++ CK_RV ret = CKR_GENERAL_ERROR; ++ X509 *cert; ++ EVP_PKEY *public_key; ++ ++ size_t id_len = strlen(id); ++ ++ { ++ FILE *f; ++ ++ f = fopen(cert_file, "r"); ++ if (f == NULL) { ++ st_logf("failed to open file %s\n", cert_file); ++ return CKR_GENERAL_ERROR; ++ } ++ ++ cert = PEM_read_X509(f, NULL, NULL, NULL); ++ fclose(f); ++ if (cert == NULL) { ++ st_logf("failed reading PEM cert\n"); ++ return CKR_GENERAL_ERROR; ++ } ++ ++ OPENSSL_ASN1_MALLOC_ENCODE(X509, cert_data, cert_length, cert, ret); ++ if (ret) ++ goto out; ++ ++ OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, issuer_data, issuer_length, ++ X509_get_issuer_name(cert), ret); ++ if (ret) ++ goto out; ++ ++ OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, subject_data, subject_length, ++ X509_get_subject_name(cert), ret); ++ if (ret) ++ goto out; ++ ++ OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, serial_data, serial_length, ++ X509_get_serialNumber(cert), ret); ++ if (ret) ++ goto out; ++ ++ } ++ ++ st_logf("done parsing, adding to internal structure\n"); ++ ++ o = add_st_object(); ++ if (o == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ o->type = STO_T_CERTIFICATE; ++ o->u.cert = cert; ++ public_key = X509_get_pubkey(o->u.cert); ++ ++ switch (EVP_PKEY_type(public_key->type)) { ++ case EVP_PKEY_RSA: ++ key_type = CKK_RSA; ++ break; ++ case EVP_PKEY_DSA: ++ key_type = CKK_DSA; ++ break; ++ default: ++ /* XXX */ ++ break; ++ } ++ ++ c = CKO_CERTIFICATE; ++ add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c)); ++ add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_LABEL, label, strlen(label)); ++ ++ add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)); ++ add_object_attribute(o, 0, CKA_ID, id, id_len); ++ ++ add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length); ++ add_object_attribute(o, 0, CKA_ISSUER, issuer_data, issuer_length); ++ add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data, serial_length); ++ add_object_attribute(o, 0, CKA_VALUE, cert_data, cert_length); ++ if (anchor) ++ add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true)); ++ else ++ add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false)); ++ ++ st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o)); ++ ++ o = add_st_object(); ++ if (o == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ o->type = STO_T_PUBLIC_KEY; ++ o->u.public_key = public_key; ++ ++ c = CKO_PUBLIC_KEY; ++ add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c)); ++ add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_LABEL, label, strlen(label)); ++ ++ add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type)); ++ add_object_attribute(o, 0, CKA_ID, id, id_len); ++ add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */ ++ add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */ ++ add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false)); ++ mech_type = CKM_RSA_X_509; ++ add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type)); ++ ++ add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length); ++ add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true)); ++ ++ add_pubkey_info(o, key_type, public_key); ++ ++ st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o)); ++ ++ if (private_key_file) { ++ CK_FLAGS flags; ++ FILE *f; ++ ++ o = add_st_object(); ++ if (o == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ o->type = STO_T_PRIVATE_KEY; ++ o->u.private_key.file = strdup(private_key_file); ++ o->u.private_key.key = NULL; ++ ++ o->u.private_key.cert = cert; ++ ++ c = CKO_PRIVATE_KEY; ++ add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c)); ++ add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_LABEL, label, strlen(label)); ++ ++ add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type)); ++ add_object_attribute(o, 0, CKA_ID, id, id_len); ++ add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */ ++ add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */ ++ add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false)); ++ mech_type = CKM_RSA_X_509; ++ add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type)); ++ ++ add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length); ++ add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true)); ++ flags = 0; ++ add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags)); ++ ++ add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false)); ++ add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true)); ++ add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false)); ++ ++ add_pubkey_info(o, key_type, public_key); ++ ++ f = fopen(private_key_file, "r"); ++ if (f == NULL) { ++ st_logf("failed to open private key\n"); ++ return CKR_GENERAL_ERROR; ++ } ++ ++ o->u.private_key.key = PEM_read_PrivateKey(f, NULL, pem_callback, NULL); ++ fclose(f); ++ if (o->u.private_key.key == NULL) { ++ st_logf("failed to read private key a startup\n"); ++ /* don't bother with this failure for now, ++ fix it at C_Login time */; ++ } else { ++ /* XXX verify keytype */ ++ ++ if (key_type == CKK_RSA) ++ RSA_set_method(o->u.private_key.key->pkey.rsa, ++ RSA_PKCS1_SSLeay()); ++ ++ if (X509_check_private_key(cert, o->u.private_key.key) != 1) { ++ EVP_PKEY_free(o->u.private_key.key); ++ o->u.private_key.key = NULL; ++ st_logf("private key doesn't verify\n"); ++ } else { ++ st_logf("private key usable\n"); ++ soft_token.flags.login_done = 1; ++ } ++ } ++ } ++ ++ ret = CKR_OK; ++ out: ++ if (ret != CKR_OK) { ++ st_logf("something went wrong when adding cert!\n"); ++ ++ /* XXX wack o */; ++ } ++ free(cert_data); ++ free(serial_data); ++ free(issuer_data); ++ free(subject_data); ++ ++ return ret; ++} ++ ++static void ++find_object_final(struct session_state *state) ++{ ++ if (state->find.attributes) { ++ CK_ULONG i; ++ ++ for (i = 0; i < state->find.num_attributes; i++) { ++ if (state->find.attributes[i].pValue) ++ free(state->find.attributes[i].pValue); ++ } ++ free(state->find.attributes); ++ state->find.attributes = NULL; ++ state->find.num_attributes = 0; ++ state->find.next_object = -1; ++ } ++} ++ ++static void ++reset_crypto_state(struct session_state *state) ++{ ++ state->encrypt_object = -1; ++ if (state->encrypt_mechanism) ++ free(state->encrypt_mechanism); ++ state->encrypt_mechanism = NULL_PTR; ++ state->decrypt_object = -1; ++ if (state->decrypt_mechanism) ++ free(state->decrypt_mechanism); ++ state->decrypt_mechanism = NULL_PTR; ++ state->sign_object = -1; ++ if (state->sign_mechanism) ++ free(state->sign_mechanism); ++ state->sign_mechanism = NULL_PTR; ++ state->verify_object = -1; ++ if (state->verify_mechanism) ++ free(state->verify_mechanism); ++ state->verify_mechanism = NULL_PTR; ++ state->digest_object = -1; ++} ++ ++static void ++close_session(struct session_state *state) ++{ ++ if (state->find.attributes) { ++ application_error("application didn't do C_FindObjectsFinal\n"); ++ find_object_final(state); ++ } ++ ++ state->session_handle = CK_INVALID_HANDLE; ++ soft_token.application = NULL_PTR; ++ soft_token.notify = NULL_PTR; ++ reset_crypto_state(state); ++} ++ ++static const char * ++has_session(void) ++{ ++ return soft_token.open_sessions > 0 ? "yes" : "no"; ++} ++ ++static void ++read_conf_file(const char *fn) ++{ ++ char buf[1024], *cert, *key, *id, *label, *s, *p; ++ int anchor; ++ FILE *f; ++ ++ f = fopen(fn, "r"); ++ if (f == NULL) { ++ st_logf("can't open configuration file %s\n", fn); ++ return; ++ } ++ ++ while(fgets(buf, sizeof(buf), f) != NULL) { ++ buf[strcspn(buf, "\n")] = '\0'; ++ ++ anchor = 0; ++ ++ st_logf("line: %s\n", buf); ++ ++ p = buf; ++ while (isspace(*p)) ++ p++; ++ if (*p == '#') ++ continue; ++ while (isspace(*p)) ++ p++; ++ ++ s = NULL; ++ id = strtok_r(p, "\t", &s); ++ if (id == NULL) ++ continue; ++ label = strtok_r(NULL, "\t", &s); ++ if (label == NULL) ++ continue; ++ cert = strtok_r(NULL, "\t", &s); ++ if (cert == NULL) ++ continue; ++ key = strtok_r(NULL, "\t", &s); ++ ++ /* XXX */ ++ if (strcmp(id, "anchor") == 0) { ++ id = "\x00\x00"; ++ anchor = 1; ++ } ++ ++ st_logf("adding: %s\n", label); ++ ++ add_certificate(label, cert, key, id, anchor); ++ } ++} ++ ++static CK_RV ++func_not_supported(void) ++{ ++ st_logf("function not supported\n"); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_Initialize(CK_VOID_PTR a) ++{ ++ CK_C_INITIALIZE_ARGS_PTR args = a; ++ st_logf("Initialize\n"); ++ int i; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ srandom(getpid() ^ time(NULL)); ++ ++ for (i = 0; i < MAX_NUM_SESSION; i++) { ++ soft_token.state[i].session_handle = CK_INVALID_HANDLE; ++ soft_token.state[i].find.attributes = NULL; ++ soft_token.state[i].find.num_attributes = 0; ++ soft_token.state[i].find.next_object = -1; ++ reset_crypto_state(&soft_token.state[i]); ++ } ++ ++ soft_token.flags.hardware_slot = 1; ++ soft_token.flags.app_error_fatal = 0; ++ soft_token.flags.login_done = 0; ++ ++ soft_token.object.objs = NULL; ++ soft_token.object.num_objs = 0; ++ ++ soft_token.logfile = NULL; ++#if 0 ++ soft_token.logfile = stdout; ++#endif ++#if 0 ++ soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a"); ++#endif ++ ++ if (a != NULL_PTR) { ++ st_logf("\tCreateMutex:\t%p\n", args->CreateMutex); ++ st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex); ++ st_logf("\tLockMutext\t%p\n", args->LockMutex); ++ st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex); ++ st_logf("\tFlags\t%04x\n", (unsigned int)args->flags); ++ } ++ ++ { ++ char *fn = NULL, *home = NULL; ++ ++ if (getuid() == geteuid()) { ++ fn = getenv("SOFTPKCS11RC"); ++ if (fn) ++ fn = strdup(fn); ++ home = getenv("HOME"); ++ } ++ if (fn == NULL && home == NULL) { ++ struct passwd *pw = getpwuid(getuid()); ++ if(pw != NULL) ++ home = pw->pw_dir; ++ } ++ if (fn == NULL) { ++ if (home) ++ asprintf(&fn, "%s/.soft-token.rc", home); ++ else ++ fn = strdup("/etc/soft-token.rc"); ++ } ++ ++ read_conf_file(fn); ++ free(fn); ++ } ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_Finalize(CK_VOID_PTR args) ++{ ++ int i; ++ ++ st_logf("Finalize\n"); ++ ++ for (i = 0; i < MAX_NUM_SESSION; i++) { ++ if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) { ++ application_error("application finalized without " ++ "closing session\n"); ++ close_session(&soft_token.state[i]); ++ } ++ } ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetInfo(CK_INFO_PTR args) ++{ ++ st_logf("GetInfo\n"); ++ ++ memset(args, 17, sizeof(*args)); ++ args->cryptokiVersion.major = 2; ++ args->cryptokiVersion.minor = 10; ++ snprintf_fill((char *)args->manufacturerID, ++ sizeof(args->manufacturerID), ++ ' ', ++ "SoftToken"); ++ snprintf_fill((char *)args->libraryDescription, ++ sizeof(args->libraryDescription), ' ', ++ "SoftToken"); ++ args->libraryVersion.major = 1; ++ args->libraryVersion.minor = 8; ++ ++ return CKR_OK; ++} ++ ++extern CK_FUNCTION_LIST funcs; ++ ++CK_RV ++C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) ++{ ++ *ppFunctionList = &funcs; ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetSlotList(CK_BBOOL tokenPresent, ++ CK_SLOT_ID_PTR pSlotList, ++ CK_ULONG_PTR pulCount) ++{ ++ st_logf("GetSlotList: %s\n", ++ tokenPresent ? "tokenPresent" : "token not Present"); ++ if (pSlotList) ++ pSlotList[0] = 1; ++ *pulCount = 1; ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetSlotInfo(CK_SLOT_ID slotID, ++ CK_SLOT_INFO_PTR pInfo) ++{ ++ st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session()); ++ ++ memset(pInfo, 18, sizeof(*pInfo)); ++ ++ if (slotID != 1) ++ return CKR_ARGUMENTS_BAD; ++ ++ snprintf_fill((char *)pInfo->slotDescription, ++ sizeof(pInfo->slotDescription), ++ ' ', ++ "SoftToken (slot)"); ++ snprintf_fill((char *)pInfo->manufacturerID, ++ sizeof(pInfo->manufacturerID), ++ ' ', ++ "SoftToken (slot)"); ++ pInfo->flags = CKF_TOKEN_PRESENT; ++ if (soft_token.flags.hardware_slot) ++ pInfo->flags |= CKF_HW_SLOT; ++ pInfo->hardwareVersion.major = 1; ++ pInfo->hardwareVersion.minor = 0; ++ pInfo->firmwareVersion.major = 1; ++ pInfo->firmwareVersion.minor = 0; ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetTokenInfo(CK_SLOT_ID slotID, ++ CK_TOKEN_INFO_PTR pInfo) ++{ ++ st_logf("GetTokenInfo: %s\n", has_session()); ++ ++ memset(pInfo, 19, sizeof(*pInfo)); ++ ++ snprintf_fill((char *)pInfo->label, ++ sizeof(pInfo->label), ++ ' ', ++ "SoftToken (token)"); ++ snprintf_fill((char *)pInfo->manufacturerID, ++ sizeof(pInfo->manufacturerID), ++ ' ', ++ "SoftToken (token)"); ++ snprintf_fill((char *)pInfo->model, ++ sizeof(pInfo->model), ++ ' ', ++ "SoftToken (token)"); ++ snprintf_fill((char *)pInfo->serialNumber, ++ sizeof(pInfo->serialNumber), ++ ' ', ++ "4711"); ++ pInfo->flags = ++ CKF_TOKEN_INITIALIZED | ++ CKF_USER_PIN_INITIALIZED; ++ ++ if (soft_token.flags.login_done == 0) ++ pInfo->flags |= CKF_LOGIN_REQUIRED; ++ ++ /* CFK_RNG | ++ CKF_RESTORE_KEY_NOT_NEEDED | ++ */ ++ pInfo->ulMaxSessionCount = MAX_NUM_SESSION; ++ pInfo->ulSessionCount = soft_token.open_sessions; ++ pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION; ++ pInfo->ulRwSessionCount = soft_token.open_sessions; ++ pInfo->ulMaxPinLen = 1024; ++ pInfo->ulMinPinLen = 0; ++ pInfo->ulTotalPublicMemory = 4711; ++ pInfo->ulFreePublicMemory = 4712; ++ pInfo->ulTotalPrivateMemory = 4713; ++ pInfo->ulFreePrivateMemory = 4714; ++ pInfo->hardwareVersion.major = 2; ++ pInfo->hardwareVersion.minor = 0; ++ pInfo->firmwareVersion.major = 2; ++ pInfo->firmwareVersion.minor = 0; ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetMechanismList(CK_SLOT_ID slotID, ++ CK_MECHANISM_TYPE_PTR pMechanismList, ++ CK_ULONG_PTR pulCount) ++{ ++ st_logf("GetMechanismList\n"); ++ ++ *pulCount = 2; ++ if (pMechanismList == NULL_PTR) ++ return CKR_OK; ++ pMechanismList[0] = CKM_RSA_X_509; ++ pMechanismList[1] = CKM_RSA_PKCS; ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetMechanismInfo(CK_SLOT_ID slotID, ++ CK_MECHANISM_TYPE type, ++ CK_MECHANISM_INFO_PTR pInfo) ++{ ++ st_logf("GetMechanismInfo: slot %d type: %d\n", ++ (int)slotID, (int)type); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_InitToken(CK_SLOT_ID slotID, ++ CK_UTF8CHAR_PTR pPin, ++ CK_ULONG ulPinLen, ++ CK_UTF8CHAR_PTR pLabel) ++{ ++ st_logf("InitToken: slot %d\n", (int)slotID); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_OpenSession(CK_SLOT_ID slotID, ++ CK_FLAGS flags, ++ CK_VOID_PTR pApplication, ++ CK_NOTIFY Notify, ++ CK_SESSION_HANDLE_PTR phSession) ++{ ++ int i; ++ ++ st_logf("OpenSession: slot: %d\n", (int)slotID); ++ ++ if (soft_token.open_sessions == MAX_NUM_SESSION) ++ return CKR_SESSION_COUNT; ++ ++ soft_token.application = pApplication; ++ soft_token.notify = Notify; ++ ++ for (i = 0; i < MAX_NUM_SESSION; i++) ++ if (soft_token.state[i].session_handle == CK_INVALID_HANDLE) ++ break; ++ if (i == MAX_NUM_SESSION) ++ abort(); ++ ++ soft_token.open_sessions++; ++ ++ soft_token.state[i].session_handle = ++ (CK_SESSION_HANDLE)(random() & 0xfffff); ++ *phSession = soft_token.state[i].session_handle; ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_CloseSession(CK_SESSION_HANDLE hSession) ++{ ++ struct session_state *state; ++ st_logf("CloseSession\n"); ++ ++ if (verify_session_handle(hSession, &state) != CKR_OK) ++ application_error("closed session not open"); ++ else ++ close_session(state); ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_CloseAllSessions(CK_SLOT_ID slotID) ++{ ++ int i; ++ ++ st_logf("CloseAllSessions\n"); ++ ++ for (i = 0; i < MAX_NUM_SESSION; i++) ++ if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) ++ close_session(&soft_token.state[i]); ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_GetSessionInfo(CK_SESSION_HANDLE hSession, ++ CK_SESSION_INFO_PTR pInfo) ++{ ++ st_logf("GetSessionInfo\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ ++ memset(pInfo, 20, sizeof(*pInfo)); ++ ++ pInfo->slotID = 1; ++ if (soft_token.flags.login_done) ++ pInfo->state = CKS_RO_USER_FUNCTIONS; ++ else ++ pInfo->state = CKS_RO_PUBLIC_SESSION; ++ pInfo->flags = CKF_SERIAL_SESSION; ++ pInfo->ulDeviceError = 0; ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_Login(CK_SESSION_HANDLE hSession, ++ CK_USER_TYPE userType, ++ CK_UTF8CHAR_PTR pPin, ++ CK_ULONG ulPinLen) ++{ ++ char *pin = NULL; ++ int i; ++ ++ st_logf("Login\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ ++ if (pPin != NULL_PTR) { ++ asprintf(&pin, "%.*s", (int)ulPinLen, pPin); ++ st_logf("type: %d password: %s\n", (int)userType, pin); ++ } ++ ++ for (i = 0; i < soft_token.object.num_objs; i++) { ++ struct st_object *o = soft_token.object.objs[i]; ++ FILE *f; ++ ++ if (o->type != STO_T_PRIVATE_KEY) ++ continue; ++ ++ if (o->u.private_key.key) ++ continue; ++ ++ f = fopen(o->u.private_key.file, "r"); ++ if (f == NULL) { ++ st_logf("can't open private file: %s\n", o->u.private_key.file); ++ continue; ++ } ++ ++ o->u.private_key.key = PEM_read_PrivateKey(f, NULL, NULL, pin); ++ fclose(f); ++ if (o->u.private_key.key == NULL) { ++ st_logf("failed to read key: %s error: %s\n", ++ o->u.private_key.file, ++ ERR_error_string(ERR_get_error(), NULL)); ++ /* just ignore failure */; ++ continue; ++ } ++ ++ /* XXX check keytype */ ++ RSA_set_method(o->u.private_key.key->pkey.rsa, RSA_PKCS1_SSLeay()); ++ ++ if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) { ++ EVP_PKEY_free(o->u.private_key.key); ++ o->u.private_key.key = NULL; ++ st_logf("private key %s doesn't verify\n", o->u.private_key.file); ++ continue; ++ } ++ ++ soft_token.flags.login_done = 1; ++ } ++ free(pin); ++ ++ return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT; ++} ++ ++CK_RV ++C_Logout(CK_SESSION_HANDLE hSession) ++{ ++ st_logf("Logout\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_GetObjectSize(CK_SESSION_HANDLE hSession, ++ CK_OBJECT_HANDLE hObject, ++ CK_ULONG_PTR pulSize) ++{ ++ st_logf("GetObjectSize\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_GetAttributeValue(CK_SESSION_HANDLE hSession, ++ CK_OBJECT_HANDLE hObject, ++ CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG ulCount) ++{ ++ struct session_state *state; ++ struct st_object *obj; ++ CK_ULONG i; ++ CK_RV ret; ++ int j; ++ ++ st_logf("GetAttributeValue: %lx\n", ++ (unsigned long)HANDLE_OBJECT_ID(hObject)); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) { ++ st_logf("object not found: %lx\n", ++ (unsigned long)HANDLE_OBJECT_ID(hObject)); ++ return ret; ++ } ++ ++ for (i = 0; i < ulCount; i++) { ++ st_logf(" getting 0x%08lx\n", (unsigned long)pTemplate[i].type); ++ for (j = 0; j < obj->num_attributes; j++) { ++ if (obj->attrs[j].secret) { ++ pTemplate[i].ulValueLen = (CK_ULONG)-1; ++ break; ++ } ++ if (pTemplate[i].type == obj->attrs[j].attribute.type) { ++ if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) { ++ if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen) ++ memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue, ++ obj->attrs[j].attribute.ulValueLen); ++ } ++ pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen; ++ break; ++ } ++ } ++ if (j == obj->num_attributes) { ++ st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type); ++ pTemplate[i].ulValueLen = (CK_ULONG)-1; ++ } ++ ++ } ++ return CKR_OK; ++} ++ ++CK_RV ++C_FindObjectsInit(CK_SESSION_HANDLE hSession, ++ CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG ulCount) ++{ ++ struct session_state *state; ++ ++ st_logf("FindObjectsInit\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->find.next_object != -1) { ++ application_error("application didn't do C_FindObjectsFinal\n"); ++ find_object_final(state); ++ } ++ if (ulCount) { ++ CK_ULONG i; ++ size_t len; ++ ++ print_attributes(pTemplate, ulCount); ++ ++ state->find.attributes = ++ calloc(1, ulCount * sizeof(state->find.attributes[0])); ++ if (state->find.attributes == NULL) ++ return CKR_DEVICE_MEMORY; ++ for (i = 0; i < ulCount; i++) { ++ state->find.attributes[i].pValue = ++ malloc(pTemplate[i].ulValueLen); ++ if (state->find.attributes[i].pValue == NULL) { ++ find_object_final(state); ++ return CKR_DEVICE_MEMORY; ++ } ++ memcpy(state->find.attributes[i].pValue, ++ pTemplate[i].pValue, pTemplate[i].ulValueLen); ++ state->find.attributes[i].type = pTemplate[i].type; ++ state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen; ++ } ++ state->find.num_attributes = ulCount; ++ state->find.next_object = 0; ++ } else { ++ st_logf("find all objects\n"); ++ state->find.attributes = NULL; ++ state->find.num_attributes = 0; ++ state->find.next_object = 0; ++ } ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_FindObjects(CK_SESSION_HANDLE hSession, ++ CK_OBJECT_HANDLE_PTR phObject, ++ CK_ULONG ulMaxObjectCount, ++ CK_ULONG_PTR pulObjectCount) ++{ ++ struct session_state *state; ++ int i; ++ ++ st_logf("FindObjects\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->find.next_object == -1) { ++ application_error("application didn't do C_FindObjectsInit\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ if (ulMaxObjectCount == 0) { ++ application_error("application asked for 0 objects\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ *pulObjectCount = 0; ++ for (i = state->find.next_object; i < soft_token.object.num_objs; i++) { ++ st_logf("FindObjects: %d\n", i); ++ state->find.next_object = i + 1; ++ if (attributes_match(soft_token.object.objs[i], ++ state->find.attributes, ++ state->find.num_attributes)) { ++ *phObject++ = soft_token.object.objs[i]->object_handle; ++ ulMaxObjectCount--; ++ (*pulObjectCount)++; ++ if (ulMaxObjectCount == 0) ++ break; ++ } ++ } ++ return CKR_OK; ++} ++ ++CK_RV ++C_FindObjectsFinal(CK_SESSION_HANDLE hSession) ++{ ++ struct session_state *state; ++ ++ st_logf("FindObjectsFinal\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ find_object_final(state); ++ return CKR_OK; ++} ++ ++static CK_RV ++commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len, ++ const CK_MECHANISM_TYPE *mechs, int mechs_len, ++ const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, ++ struct st_object **o) ++{ ++ CK_RV ret; ++ int i; ++ ++ *o = NULL; ++ if ((ret = object_handle_to_object(hKey, o)) != CKR_OK) ++ return ret; ++ ++ ret = attributes_match(*o, attr_match, attr_match_len); ++ if (!ret) { ++ application_error("called commonInit on key that doesn't " ++ "support required attr"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ for (i = 0; i < mechs_len; i++) ++ if (mechs[i] == pMechanism->mechanism) ++ break; ++ if (i == mechs_len) { ++ application_error("called mech (%08lx) not supported\n", ++ pMechanism->mechanism); ++ return CKR_ARGUMENTS_BAD; ++ } ++ return CKR_OK; ++} ++ ++ ++static CK_RV ++dup_mechanism(CK_MECHANISM_PTR *dup, const CK_MECHANISM_PTR pMechanism) ++{ ++ CK_MECHANISM_PTR p; ++ ++ p = malloc(sizeof(*p)); ++ if (p == NULL) ++ return CKR_DEVICE_MEMORY; ++ ++ if (*dup) ++ free(*dup); ++ *dup = p; ++ memcpy(p, pMechanism, sizeof(*p)); ++ ++ return CKR_OK; ++} ++ ++ ++CK_RV ++C_EncryptInit(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ struct session_state *state; ++ CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 }; ++ CK_BBOOL bool_true = CK_TRUE; ++ CK_ATTRIBUTE attr[] = { ++ { CKA_ENCRYPT, &bool_true, sizeof(bool_true) } ++ }; ++ struct st_object *o; ++ CK_RV ret; ++ ++ st_logf("EncryptInit\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), ++ mechs, sizeof(mechs)/sizeof(mechs[0]), ++ pMechanism, hKey, &o); ++ if (ret) ++ return ret; ++ ++ ret = dup_mechanism(&state->encrypt_mechanism, pMechanism); ++ if (ret == CKR_OK) ++ state->encrypt_object = OBJECT_ID(o); ++ ++ return ret; ++} ++ ++CK_RV ++C_Encrypt(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, ++ CK_BYTE_PTR pEncryptedData, ++ CK_ULONG_PTR pulEncryptedDataLen) ++{ ++ struct session_state *state; ++ struct st_object *o; ++ void *buffer = NULL; ++ CK_RV ret; ++ RSA *rsa; ++ int padding, len, buffer_len, padding_len; ++ ++ st_logf("Encrypt\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->encrypt_object == -1) ++ return CKR_ARGUMENTS_BAD; ++ ++ o = soft_token.object.objs[state->encrypt_object]; ++ ++ if (o->u.public_key == NULL) { ++ st_logf("public key NULL\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ rsa = o->u.public_key->pkey.rsa; ++ ++ if (rsa == NULL) ++ return CKR_ARGUMENTS_BAD; ++ ++ RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */ ++ ++ buffer_len = RSA_size(rsa); ++ ++ buffer = malloc(buffer_len); ++ if (buffer == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ ++ ret = CKR_OK; ++ switch(state->encrypt_mechanism->mechanism) { ++ case CKM_RSA_PKCS: ++ padding = RSA_PKCS1_PADDING; ++ padding_len = RSA_PKCS1_PADDING_SIZE; ++ break; ++ case CKM_RSA_X_509: ++ padding = RSA_NO_PADDING; ++ padding_len = 0; ++ break; ++ default: ++ ret = CKR_FUNCTION_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (buffer_len + padding_len < ulDataLen) { ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pulEncryptedDataLen == NULL) { ++ st_logf("pulEncryptedDataLen NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pData == NULL_PTR) { ++ st_logf("data NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ len = RSA_public_encrypt(ulDataLen, pData, buffer, rsa, padding); ++ if (len <= 0) { ++ ret = CKR_DEVICE_ERROR; ++ goto out; ++ } ++ if (len > buffer_len) ++ abort(); ++ ++ if (pEncryptedData != NULL_PTR) ++ memcpy(pEncryptedData, buffer, len); ++ *pulEncryptedDataLen = len; ++ ++ out: ++ if (buffer) { ++ memset(buffer, 0, buffer_len); ++ free(buffer); ++ } ++ return ret; ++} ++ ++CK_RV ++C_EncryptUpdate(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen, ++ CK_BYTE_PTR pEncryptedPart, ++ CK_ULONG_PTR pulEncryptedPartLen) ++{ ++ st_logf("EncryptUpdate\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++ ++CK_RV ++C_EncryptFinal(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pLastEncryptedPart, ++ CK_ULONG_PTR pulLastEncryptedPartLen) ++{ ++ st_logf("EncryptFinal\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++ ++/* C_DecryptInit initializes a decryption operation. */ ++CK_RV ++C_DecryptInit(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ struct session_state *state; ++ CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 }; ++ CK_BBOOL bool_true = CK_TRUE; ++ CK_ATTRIBUTE attr[] = { ++ { CKA_DECRYPT, &bool_true, sizeof(bool_true) } ++ }; ++ struct st_object *o; ++ CK_RV ret; ++ ++ st_logf("DecryptInit\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), ++ mechs, sizeof(mechs)/sizeof(mechs[0]), ++ pMechanism, hKey, &o); ++ if (ret) ++ return ret; ++ ++ ret = dup_mechanism(&state->decrypt_mechanism, pMechanism); ++ if (ret == CKR_OK) ++ state->decrypt_object = OBJECT_ID(o); ++ ++ return CKR_OK; ++} ++ ++ ++CK_RV ++C_Decrypt(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pEncryptedData, ++ CK_ULONG ulEncryptedDataLen, ++ CK_BYTE_PTR pData, ++ CK_ULONG_PTR pulDataLen) ++{ ++ struct session_state *state; ++ struct st_object *o; ++ void *buffer = NULL; ++ CK_RV ret; ++ RSA *rsa; ++ int padding, len, buffer_len, padding_len; ++ ++ st_logf("Decrypt\n"); ++ ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->decrypt_object == -1) ++ return CKR_ARGUMENTS_BAD; ++ ++ o = soft_token.object.objs[state->decrypt_object]; ++ ++ if (o->u.private_key.key == NULL) { ++ st_logf("private key NULL\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ rsa = o->u.private_key.key->pkey.rsa; ++ ++ if (rsa == NULL) ++ return CKR_ARGUMENTS_BAD; ++ ++ RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */ ++ ++ buffer_len = RSA_size(rsa); ++ ++ buffer = malloc(buffer_len); ++ if (buffer == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ ++ ret = CKR_OK; ++ switch(state->decrypt_mechanism->mechanism) { ++ case CKM_RSA_PKCS: ++ padding = RSA_PKCS1_PADDING; ++ padding_len = RSA_PKCS1_PADDING_SIZE; ++ break; ++ case CKM_RSA_X_509: ++ padding = RSA_NO_PADDING; ++ padding_len = 0; ++ break; ++ default: ++ ret = CKR_FUNCTION_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (buffer_len + padding_len < ulEncryptedDataLen) { ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pulDataLen == NULL) { ++ st_logf("pulDataLen NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pEncryptedData == NULL_PTR) { ++ st_logf("data NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ len = RSA_private_decrypt(ulEncryptedDataLen, pEncryptedData, buffer, ++ rsa, padding); ++ if (len <= 0) { ++ ret = CKR_DEVICE_ERROR; ++ goto out; ++ } ++ if (len > buffer_len) ++ abort(); ++ ++ if (pData != NULL_PTR) ++ memcpy(pData, buffer, len); ++ *pulDataLen = len; ++ ++ out: ++ if (buffer) { ++ memset(buffer, 0, buffer_len); ++ free(buffer); ++ } ++ return ret; ++} ++ ++ ++CK_RV ++C_DecryptUpdate(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pEncryptedPart, ++ CK_ULONG ulEncryptedPartLen, ++ CK_BYTE_PTR pPart, ++ CK_ULONG_PTR pulPartLen) ++ ++{ ++ st_logf("DecryptUpdate\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++ ++CK_RV ++C_DecryptFinal(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pLastPart, ++ CK_ULONG_PTR pulLastPartLen) ++{ ++ st_logf("DecryptFinal\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_DigestInit(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism) ++{ ++ st_logf("DigestInit\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_SignInit(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ struct session_state *state; ++ CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 }; ++ CK_BBOOL bool_true = CK_TRUE; ++ CK_ATTRIBUTE attr[] = { ++ { CKA_SIGN, &bool_true, sizeof(bool_true) } ++ }; ++ struct st_object *o; ++ CK_RV ret; ++ ++ st_logf("SignInit\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), ++ mechs, sizeof(mechs)/sizeof(mechs[0]), ++ pMechanism, hKey, &o); ++ if (ret) ++ return ret; ++ ++ ret = dup_mechanism(&state->sign_mechanism, pMechanism); ++ if (ret == CKR_OK) ++ state->sign_object = OBJECT_ID(o); ++ ++ return CKR_OK; ++} ++ ++CK_RV ++C_Sign(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, ++ CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen) ++{ ++ struct session_state *state; ++ struct st_object *o; ++ void *buffer = NULL; ++ CK_RV ret; ++ RSA *rsa; ++ int padding, len, buffer_len, padding_len; ++ ++ st_logf("Sign\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->sign_object == -1) ++ return CKR_ARGUMENTS_BAD; ++ ++ o = soft_token.object.objs[state->sign_object]; ++ ++ if (o->u.private_key.key == NULL) { ++ st_logf("private key NULL\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ rsa = o->u.private_key.key->pkey.rsa; ++ ++ if (rsa == NULL) ++ return CKR_ARGUMENTS_BAD; ++ ++ RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */ ++ ++ buffer_len = RSA_size(rsa); ++ ++ buffer = malloc(buffer_len); ++ if (buffer == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ ++ switch(state->sign_mechanism->mechanism) { ++ case CKM_RSA_PKCS: ++ padding = RSA_PKCS1_PADDING; ++ padding_len = RSA_PKCS1_PADDING_SIZE; ++ break; ++ case CKM_RSA_X_509: ++ padding = RSA_NO_PADDING; ++ padding_len = 0; ++ break; ++ default: ++ ret = CKR_FUNCTION_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (buffer_len < ulDataLen + padding_len) { ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pulSignatureLen == NULL) { ++ st_logf("signature len NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pData == NULL_PTR) { ++ st_logf("data NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ len = RSA_private_encrypt(ulDataLen, pData, buffer, rsa, padding); ++ st_logf("private encrypt done\n"); ++ if (len <= 0) { ++ ret = CKR_DEVICE_ERROR; ++ goto out; ++ } ++ if (len > buffer_len) ++ abort(); ++ ++ if (pSignature != NULL_PTR) ++ memcpy(pSignature, buffer, len); ++ *pulSignatureLen = len; ++ ++ ret = CKR_OK; ++ ++ out: ++ if (buffer) { ++ memset(buffer, 0, buffer_len); ++ free(buffer); ++ } ++ return ret; ++} ++ ++CK_RV ++C_SignUpdate(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen) ++{ ++ st_logf("SignUpdate\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++ ++CK_RV ++C_SignFinal(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen) ++{ ++ st_logf("SignUpdate\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_VerifyInit(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ struct session_state *state; ++ CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 }; ++ CK_BBOOL bool_true = CK_TRUE; ++ CK_ATTRIBUTE attr[] = { ++ { CKA_VERIFY, &bool_true, sizeof(bool_true) } ++ }; ++ struct st_object *o; ++ CK_RV ret; ++ ++ st_logf("VerifyInit\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), ++ mechs, sizeof(mechs)/sizeof(mechs[0]), ++ pMechanism, hKey, &o); ++ if (ret) ++ return ret; ++ ++ ret = dup_mechanism(&state->verify_mechanism, pMechanism); ++ if (ret == CKR_OK) ++ state->verify_object = OBJECT_ID(o); ++ ++ return ret; ++} ++ ++CK_RV ++C_Verify(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, ++ CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen) ++{ ++ struct session_state *state; ++ struct st_object *o; ++ void *buffer = NULL; ++ CK_RV ret; ++ RSA *rsa; ++ int padding, len, buffer_len; ++ ++ st_logf("Verify\n"); ++ VERIFY_SESSION_HANDLE(hSession, &state); ++ ++ if (state->verify_object == -1) ++ return CKR_ARGUMENTS_BAD; ++ ++ o = soft_token.object.objs[state->verify_object]; ++ ++ if (o->u.public_key == NULL) { ++ st_logf("public key NULL\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ rsa = o->u.public_key->pkey.rsa; ++ ++ if (rsa == NULL) ++ return CKR_ARGUMENTS_BAD; ++ ++ RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */ ++ ++ buffer_len = RSA_size(rsa); ++ ++ buffer = malloc(buffer_len); ++ if (buffer == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } ++ ++ ret = CKR_OK; ++ switch(state->verify_mechanism->mechanism) { ++ case CKM_RSA_PKCS: ++ padding = RSA_PKCS1_PADDING; ++ break; ++ case CKM_RSA_X_509: ++ padding = RSA_NO_PADDING; ++ break; ++ default: ++ ret = CKR_FUNCTION_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (buffer_len < ulDataLen) { ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pSignature == NULL) { ++ st_logf("signature NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ if (pData == NULL_PTR) { ++ st_logf("data NULL\n"); ++ ret = CKR_ARGUMENTS_BAD; ++ goto out; ++ } ++ ++ len = RSA_public_decrypt(ulDataLen, pData, buffer, rsa, padding); ++ st_logf("private encrypt done\n"); ++ if (len <= 0) { ++ ret = CKR_DEVICE_ERROR; ++ goto out; ++ } ++ if (len > buffer_len) ++ abort(); ++ ++ if (len != ulSignatureLen) { ++ ret = CKR_GENERAL_ERROR; ++ goto out; ++ } ++ ++ if (memcmp(pSignature, buffer, len) != 0) { ++ ret = CKR_GENERAL_ERROR; ++ goto out; ++ } ++ ++ out: ++ if (buffer) { ++ memset(buffer, 0, buffer_len); ++ free(buffer); ++ } ++ return ret; ++} ++ ++ ++CK_RV ++C_VerifyUpdate(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen) ++{ ++ st_logf("VerifyUpdate\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_VerifyFinal(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen) ++{ ++ st_logf("VerifyFinal\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++CK_RV ++C_GenerateRandom(CK_SESSION_HANDLE hSession, ++ CK_BYTE_PTR RandomData, ++ CK_ULONG ulRandomLen) ++{ ++ st_logf("GenerateRandom\n"); ++ VERIFY_SESSION_HANDLE(hSession, NULL); ++ return CKR_FUNCTION_NOT_SUPPORTED; ++} ++ ++ ++CK_FUNCTION_LIST funcs = { ++ { 2, 11 }, ++ C_Initialize, ++ C_Finalize, ++ C_GetInfo, ++ C_GetFunctionList, ++ C_GetSlotList, ++ C_GetSlotInfo, ++ C_GetTokenInfo, ++ C_GetMechanismList, ++ C_GetMechanismInfo, ++ C_InitToken, ++ (void *)func_not_supported, /* C_InitPIN */ ++ (void *)func_not_supported, /* C_SetPIN */ ++ C_OpenSession, ++ C_CloseSession, ++ C_CloseAllSessions, ++ C_GetSessionInfo, ++ (void *)func_not_supported, /* C_GetOperationState */ ++ (void *)func_not_supported, /* C_SetOperationState */ ++ C_Login, ++ C_Logout, ++ (void *)func_not_supported, /* C_CreateObject */ ++ (void *)func_not_supported, /* C_CopyObject */ ++ (void *)func_not_supported, /* C_DestroyObject */ ++ (void *)func_not_supported, /* C_GetObjectSize */ ++ C_GetAttributeValue, ++ (void *)func_not_supported, /* C_SetAttributeValue */ ++ C_FindObjectsInit, ++ C_FindObjects, ++ C_FindObjectsFinal, ++ C_EncryptInit, ++ C_Encrypt, ++ C_EncryptUpdate, ++ C_EncryptFinal, ++ C_DecryptInit, ++ C_Decrypt, ++ C_DecryptUpdate, ++ C_DecryptFinal, ++ C_DigestInit, ++ (void *)func_not_supported, /* C_Digest */ ++ (void *)func_not_supported, /* C_DigestUpdate */ ++ (void *)func_not_supported, /* C_DigestKey */ ++ (void *)func_not_supported, /* C_DigestFinal */ ++ C_SignInit, ++ C_Sign, ++ C_SignUpdate, ++ C_SignFinal, ++ (void *)func_not_supported, /* C_SignRecoverInit */ ++ (void *)func_not_supported, /* C_SignRecover */ ++ C_VerifyInit, ++ C_Verify, ++ C_VerifyUpdate, ++ C_VerifyFinal, ++ (void *)func_not_supported, /* C_VerifyRecoverInit */ ++ (void *)func_not_supported, /* C_VerifyRecover */ ++ (void *)func_not_supported, /* C_DigestEncryptUpdate */ ++ (void *)func_not_supported, /* C_DecryptDigestUpdate */ ++ (void *)func_not_supported, /* C_SignEncryptUpdate */ ++ (void *)func_not_supported, /* C_DecryptVerifyUpdate */ ++ (void *)func_not_supported, /* C_GenerateKey */ ++ (void *)func_not_supported, /* C_GenerateKeyPair */ ++ (void *)func_not_supported, /* C_WrapKey */ ++ (void *)func_not_supported, /* C_UnwrapKey */ ++ (void *)func_not_supported, /* C_DeriveKey */ ++ (void *)func_not_supported, /* C_SeedRandom */ ++ C_GenerateRandom, ++ (void *)func_not_supported, /* C_GetFunctionStatus */ ++ (void *)func_not_supported, /* C_CancelFunction */ ++ (void *)func_not_supported /* C_WaitForSlotEvent */ ++}; diff --git a/SOURCES/Add-tests-for-KCM-ccache-type.patch b/SOURCES/Add-tests-for-KCM-ccache-type.patch index 8aa8f23..f572041 100644 --- a/SOURCES/Add-tests-for-KCM-ccache-type.patch +++ b/SOURCES/Add-tests-for-KCM-ccache-type.patch @@ -1,4 +1,4 @@ -From dd863eb4311310c23ee12961fa8e91703f29a6f5 Mon Sep 17 00:00:00 2001 +From 7ab0bbac058d2b82aa3432759c600b22012f8afe Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Thu, 22 Nov 2018 00:27:35 -0500 Subject: [PATCH] Add tests for KCM ccache type diff --git a/SOURCES/Address-some-optimized-out-memset-calls.patch b/SOURCES/Address-some-optimized-out-memset-calls.patch index 58b1b25..372e527 100644 --- a/SOURCES/Address-some-optimized-out-memset-calls.patch +++ b/SOURCES/Address-some-optimized-out-memset-calls.patch @@ -1,4 +1,4 @@ -From 54348bbfaec50bb72d1625c015f8e5c4cfa59e0d Mon Sep 17 00:00:00 2001 +From 722247aa6201d18a7ee69c4a9a05315226fe6383 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Sun, 30 Dec 2018 16:40:28 -0500 Subject: [PATCH] Address some optimized-out memset() calls diff --git a/SOURCES/Avoid-alignment-warnings-in-openssl-rc4.c.patch b/SOURCES/Avoid-alignment-warnings-in-openssl-rc4.c.patch new file mode 100644 index 0000000..e684c88 --- /dev/null +++ b/SOURCES/Avoid-alignment-warnings-in-openssl-rc4.c.patch @@ -0,0 +1,63 @@ +From e22f3e2439903aa05321ca339be6a12067b2c4db Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Mon, 6 May 2019 15:14:49 -0400 +Subject: [PATCH] Avoid alignment warnings in openssl rc4.c + +Add a comment to k5_arcfour_init_state() explaining how we stretch the +krb5_data cipher state contract. Use void * casts when interpreting +the data pointer to avoid alignment warnings. + +[ghudson@mit.edu: moved and expanded comment; rewrote commit message] + +(cherry picked from commit 1cd41d76c12fc1cea0a8bf0d6a40f34623c60d6d) +--- + src/lib/crypto/openssl/enc_provider/rc4.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c +index 7f3c086ed..a65d57b7a 100644 +--- a/src/lib/crypto/openssl/enc_provider/rc4.c ++++ b/src/lib/crypto/openssl/enc_provider/rc4.c +@@ -57,7 +57,7 @@ struct arcfour_state { + + /* In-place IOV crypto */ + static krb5_error_code +-k5_arcfour_docrypt(krb5_key key,const krb5_data *state, krb5_crypto_iov *data, ++k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data, + size_t num_data) + { + size_t i; +@@ -66,7 +66,7 @@ k5_arcfour_docrypt(krb5_key key,const krb5_data *state, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx = NULL; + struct arcfour_state *arcstate; + +- arcstate = (state != NULL) ? (struct arcfour_state *) state->data : NULL; ++ arcstate = (state != NULL) ? (void *)state->data : NULL; + if (arcstate != NULL) { + ctx = arcstate->ctx; + if (arcstate->loopback != arcstate) +@@ -113,7 +113,7 @@ k5_arcfour_docrypt(krb5_key key,const krb5_data *state, krb5_crypto_iov *data, + static void + k5_arcfour_free_state(krb5_data *state) + { +- struct arcfour_state *arcstate = (struct arcfour_state *) state->data; ++ struct arcfour_state *arcstate = (void *)state->data; + + EVP_CIPHER_CTX_free(arcstate->ctx); + free(arcstate); +@@ -125,6 +125,15 @@ k5_arcfour_init_state(const krb5_keyblock *key, + { + struct arcfour_state *arcstate; + ++ /* ++ * The cipher state here is a saved pointer to a struct arcfour_state ++ * object, rather than a flat byte array as in most enc providers. The ++ * object includes a loopback pointer to detect if if the caller made a ++ * copy of the krb5_data value or otherwise assumed it was a simple byte ++ * array. When we cast the data pointer back, we need to go through void * ++ * to avoid increased alignment warnings. ++ */ ++ + /* Create a state structure with an uninitialized context. */ + arcstate = calloc(1, sizeof(*arcstate)); + if (arcstate == NULL) diff --git a/SOURCES/Become-FIPS-aware-with-3DES.patch b/SOURCES/Become-FIPS-aware-with-3DES.patch deleted file mode 100644 index 02ffa7b..0000000 --- a/SOURCES/Become-FIPS-aware-with-3DES.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 0c361343839b2ff6f89f1ee9c1e01d4f05ab6ffe Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 9 Nov 2018 15:12:21 -0500 -Subject: [PATCH] Become FIPS-aware (with 3DES) - -A lot of the FIPS error conditions from OpenSSL are incredibly -mysterious (at best, things return NULL unexpectedly; at worst, -internal assertions are tripped; most of the time, you just get -ENOMEM). In order to cope with this, we need to have some level of -awareness of what we can and can't safely call. - -This will slow down some calls slightly (FIPS_mode() takes multiple -locks), but not for any crypto we care about - which is to say that -AES is fine. - -(cherry picked from commit 9f5fbf191d74cae9b28d318fff4c80d3d3e49c86) ---- - src/lib/crypto/openssl/enc_provider/camellia.c | 6 ++++++ - src/lib/crypto/openssl/enc_provider/des.c | 9 +++++++++ - src/lib/crypto/openssl/enc_provider/des3.c | 6 ++++++ - src/lib/crypto/openssl/enc_provider/rc4.c | 13 ++++++++++++- - src/lib/crypto/openssl/hash_provider/hash_evp.c | 4 ++++ - src/lib/crypto/openssl/hmac.c | 6 +++++- - 6 files changed, 42 insertions(+), 2 deletions(-) - -diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c -index 2da691329..f79679a0b 100644 ---- a/src/lib/crypto/openssl/enc_provider/camellia.c -+++ b/src/lib/crypto/openssl/enc_provider/camellia.c -@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data, - unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE]; - struct iov_cursor cursor; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - if (output->length < CAMELLIA_BLOCK_SIZE) - return KRB5_BAD_MSIZE; - -@@ -331,6 +334,9 @@ static krb5_error_code - krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage, - krb5_data *state) - { -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - state->length = 16; - state->data = (void *) malloc(16); - if (state->data == NULL) -diff --git a/src/lib/crypto/openssl/enc_provider/des.c b/src/lib/crypto/openssl/enc_provider/des.c -index a662db512..7d17d287e 100644 ---- a/src/lib/crypto/openssl/enc_provider/des.c -+++ b/src/lib/crypto/openssl/enc_provider/des.c -@@ -85,6 +85,9 @@ k5_des_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, - EVP_CIPHER_CTX *ctx; - krb5_boolean empty; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - ret = validate(key, ivec, data, num_data, &empty); - if (ret != 0 || empty) - return ret; -@@ -133,6 +136,9 @@ k5_des_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, - EVP_CIPHER_CTX *ctx; - krb5_boolean empty; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - ret = validate(key, ivec, data, num_data, &empty); - if (ret != 0 || empty) - return ret; -@@ -182,6 +188,9 @@ k5_des_cbc_mac(krb5_key key, const krb5_crypto_iov *data, size_t num_data, - DES_key_schedule sched; - krb5_boolean empty; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - ret = validate(key, ivec, data, num_data, &empty); - if (ret != 0) - return ret; -diff --git a/src/lib/crypto/openssl/enc_provider/des3.c b/src/lib/crypto/openssl/enc_provider/des3.c -index 1c439c2cd..8be555a8d 100644 ---- a/src/lib/crypto/openssl/enc_provider/des3.c -+++ b/src/lib/crypto/openssl/enc_provider/des3.c -@@ -84,6 +84,9 @@ k5_des3_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, - EVP_CIPHER_CTX *ctx; - krb5_boolean empty; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - ret = validate(key, ivec, data, num_data, &empty); - if (ret != 0 || empty) - return ret; -@@ -133,6 +136,9 @@ k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, - EVP_CIPHER_CTX *ctx; - krb5_boolean empty; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - ret = validate(key, ivec, data, num_data, &empty); - if (ret != 0 || empty) - return ret; -diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c -index 7f3c086ed..a3f2a7442 100644 ---- a/src/lib/crypto/openssl/enc_provider/rc4.c -+++ b/src/lib/crypto/openssl/enc_provider/rc4.c -@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key,const krb5_data *state, krb5_crypto_iov *data, - EVP_CIPHER_CTX *ctx = NULL; - struct arcfour_state *arcstate; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - arcstate = (state != NULL) ? (struct arcfour_state *) state->data : NULL; - if (arcstate != NULL) { - ctx = arcstate->ctx; -@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key,const krb5_data *state, krb5_crypto_iov *data, - static void - k5_arcfour_free_state(krb5_data *state) - { -- struct arcfour_state *arcstate = (struct arcfour_state *) state->data; -+ struct arcfour_state *arcstate; -+ -+ if (FIPS_mode()) -+ return; -+ -+ arcstate = (struct arcfour_state *) state->data; - - EVP_CIPHER_CTX_free(arcstate->ctx); - free(arcstate); -@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key, - { - struct arcfour_state *arcstate; - -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; -+ - /* Create a state structure with an uninitialized context. */ - arcstate = calloc(1, sizeof(*arcstate)); - if (arcstate == NULL) -diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c -index 957ed8d9c..8c1fd7f59 100644 ---- a/src/lib/crypto/openssl/hash_provider/hash_evp.c -+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c -@@ -64,12 +64,16 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data, - static krb5_error_code - hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) - { -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; - return hash_evp(EVP_md4(), data, num_data, output); - } - - static krb5_error_code - hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) - { -+ if (FIPS_mode()) -+ return KRB5_CRYPTO_INTERNAL; - return hash_evp(EVP_md5(), data, num_data, output); - } - -diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c -index b2db6ec02..d94d9ac94 100644 ---- a/src/lib/crypto/openssl/hmac.c -+++ b/src/lib/crypto/openssl/hmac.c -@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash) - return EVP_sha256(); - else if (!strncmp(hash->hash_name, "SHA-384",7)) - return EVP_sha384(); -- else if (!strncmp(hash->hash_name, "MD5", 3)) -+ -+ if (FIPS_mode()) -+ return NULL; -+ -+ if (!strncmp(hash->hash_name, "MD5", 3)) - return EVP_md5(); - else if (!strncmp(hash->hash_name, "MD4", 3)) - return EVP_md4(); diff --git a/SOURCES/FIPS-aware-SPAKE-group-negotiation.patch b/SOURCES/FIPS-aware-SPAKE-group-negotiation.patch deleted file mode 100644 index f7bb807..0000000 --- a/SOURCES/FIPS-aware-SPAKE-group-negotiation.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 5b4467a2c47e6de814e69ec3eb4c3e7a4632119c Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Mon, 1 Apr 2019 13:13:09 -0400 -Subject: [PATCH] FIPS-aware SPAKE group negotiation - -(cherry picked from commit 59269fca96168aa89dc32834d188a54eea8953ac) ---- - src/plugins/preauth/spake/groups.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/src/plugins/preauth/spake/groups.c b/src/plugins/preauth/spake/groups.c -index a195cc195..8a913cb5a 100644 ---- a/src/plugins/preauth/spake/groups.c -+++ b/src/plugins/preauth/spake/groups.c -@@ -56,6 +56,8 @@ - #include "trace.h" - #include "groups.h" - -+#include -+ - #define DEFAULT_GROUPS_CLIENT "edwards25519" - #define DEFAULT_GROUPS_KDC "" - -@@ -102,6 +104,9 @@ find_gdef(int32_t group) - { - size_t i; - -+ if (group == builtin_edwards25519.reg->id && FIPS_mode()) -+ return NULL; -+ - for (i = 0; groupdefs[i] != NULL; i++) { - if (groupdefs[i]->reg->id == group) - return groupdefs[i]; -@@ -116,6 +121,9 @@ find_gnum(const char *name) - { - size_t i; - -+ if (strcasecmp(name, builtin_edwards25519.reg->name) == 0 && FIPS_mode()) -+ return 0; -+ - for (i = 0; groupdefs[i] != NULL; i++) { - if (strcasecmp(name, groupdefs[i]->reg->name) == 0) - return groupdefs[i]->reg->id; diff --git a/SOURCES/Fix-Coverity-defects-in-soft-pkcs11-test-code.patch b/SOURCES/Fix-Coverity-defects-in-soft-pkcs11-test-code.patch new file mode 100644 index 0000000..359335d --- /dev/null +++ b/SOURCES/Fix-Coverity-defects-in-soft-pkcs11-test-code.patch @@ -0,0 +1,207 @@ +From 44b429df9ac4bb8ad84a090fee1bd70d83adcf23 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 20 Jul 2019 00:51:52 -0400 +Subject: [PATCH] Fix Coverity defects in soft-pkcs11 test code + +Nothing in the code removes objects from soft_token.object.obs, so +simplify add_st_object() not to search for an empty slot. Avoid using +random() by using a counter for session handles and just the array +slot number for object handles. Add a helper get_rcfilename() to +facilitate checking the result of asprintf(). Properly initialize ap +in sprintf_fill(). Close the file handle in read_conf_file(). + +(cherry picked from commit b4831515b2f3b6fd7d7fd4bff4558c10c710891d) +(cherry picked from commit 28db01445d2807d51b5045c0a04d5e49905de504) +--- + src/tests/softpkcs11/main.c | 102 +++++++++++++++++++----------------- + 1 file changed, 53 insertions(+), 49 deletions(-) + +diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c +index 5255323d3..2d1448ca2 100644 +--- a/src/tests/softpkcs11/main.c ++++ b/src/tests/softpkcs11/main.c +@@ -78,6 +78,7 @@ compat_rsa_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, + (BL) = i2d_##T((S), &p); \ + if ((BL) <= 0) { \ + free((B)); \ ++ (B) = NULL; \ + (R) = EINVAL; \ + } \ + } \ +@@ -149,6 +150,7 @@ static struct soft_token { + } state[10]; + #define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0])) + FILE *logfile; ++ CK_SESSION_HANDLE next_session_handle; + } soft_token; + + static void +@@ -179,6 +181,7 @@ snprintf_fill(char *str, int size, char fillchar, const char *fmt, ...) + { + int len; + va_list ap; ++ va_start(ap, fmt); + len = vsnprintf(str, size, fmt, ap); + va_end(ap); + if (len < 0 || len > size) +@@ -344,7 +347,13 @@ static struct st_object * + add_st_object(void) + { + struct st_object *o, **objs; +- int i; ++ ++ objs = realloc(soft_token.object.objs, ++ (soft_token.object.num_objs + 1) * ++ sizeof(soft_token.object.objs[0])); ++ if (objs == NULL) ++ return NULL; ++ soft_token.object.objs = objs; + + o = malloc(sizeof(*o)); + if (o == NULL) +@@ -352,26 +361,9 @@ add_st_object(void) + memset(o, 0, sizeof(*o)); + o->attrs = NULL; + o->num_attributes = 0; ++ o->object_handle = soft_token.object.num_objs; + +- for (i = 0; i < soft_token.object.num_objs; i++) { +- if (soft_token.object.objs == NULL) { +- soft_token.object.objs[i] = o; +- break; +- } +- } +- if (i == soft_token.object.num_objs) { +- objs = realloc(soft_token.object.objs, +- (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0])); +- if (objs == NULL) { +- free(o); +- return NULL; +- } +- soft_token.object.objs = objs; +- soft_token.object.objs[soft_token.object.num_objs++] = o; +- } +- soft_token.object.objs[i]->object_handle = +- (random() & (~OBJECT_ID_MASK)) | i; +- ++ soft_token.object.objs[soft_token.object.num_objs++] = o; + return o; + } + +@@ -797,6 +789,8 @@ read_conf_file(const char *fn) + + add_certificate(label, cert, key, id, anchor); + } ++ ++ fclose(f); + } + + static CK_RV +@@ -806,19 +800,47 @@ func_not_supported(void) + return CKR_FUNCTION_NOT_SUPPORTED; + } + ++static char * ++get_rcfilename() ++{ ++ struct passwd *pw; ++ const char *home = NULL; ++ char *fn; ++ ++ if (getuid() == geteuid()) { ++ fn = getenv("SOFTPKCS11RC"); ++ if (fn != NULL) ++ return strdup(fn); ++ ++ home = getenv("HOME"); ++ } ++ ++ if (home == NULL) { ++ pw = getpwuid(getuid()); ++ if (pw != NULL) ++ home = pw->pw_dir; ++ } ++ ++ if (home == NULL) ++ return strdup("/etc/soft-token.rc"); ++ ++ if (asprintf(&fn, "%s/.soft-token.rc", home) < 0) ++ return NULL; ++ return fn; ++} ++ + CK_RV + C_Initialize(CK_VOID_PTR a) + { + CK_C_INITIALIZE_ARGS_PTR args = a; + size_t i; ++ char *fn; + + st_logf("Initialize\n"); + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + +- srandom(getpid() ^ time(NULL)); +- + for (i = 0; i < MAX_NUM_SESSION; i++) { + soft_token.state[i].session_handle = CK_INVALID_HANDLE; + soft_token.state[i].find.attributes = NULL; +@@ -850,31 +872,13 @@ C_Initialize(CK_VOID_PTR a) + st_logf("\tFlags\t%04x\n", (unsigned int)args->flags); + } + +- { +- char *fn = NULL, *home = NULL; +- +- if (getuid() == geteuid()) { +- fn = getenv("SOFTPKCS11RC"); +- if (fn) +- fn = strdup(fn); +- home = getenv("HOME"); +- } +- if (fn == NULL && home == NULL) { +- struct passwd *pw = getpwuid(getuid()); +- if(pw != NULL) +- home = pw->pw_dir; +- } +- if (fn == NULL) { +- if (home) +- asprintf(&fn, "%s/.soft-token.rc", home); +- else +- fn = strdup("/etc/soft-token.rc"); +- } +- +- read_conf_file(fn); +- free(fn); +- } ++ soft_token.next_session_handle = 0; + ++ fn = get_rcfilename(); ++ if (fn == NULL) ++ return CKR_DEVICE_MEMORY; ++ read_conf_file(fn); ++ free(fn); + return CKR_OK; + } + +@@ -1082,8 +1086,7 @@ C_OpenSession(CK_SLOT_ID slotID, + + soft_token.open_sessions++; + +- soft_token.state[i].session_handle = +- (CK_SESSION_HANDLE)(random() & 0xfffff); ++ soft_token.state[i].session_handle = soft_token.next_session_handle++; + *phSession = soft_token.state[i].session_handle; + + return CKR_OK; +@@ -1152,7 +1155,8 @@ C_Login(CK_SESSION_HANDLE hSession, + VERIFY_SESSION_HANDLE(hSession, NULL); + + if (pPin != NULL_PTR) { +- asprintf(&pin, "%.*s", (int)ulPinLen, pPin); ++ if (asprintf(&pin, "%.*s", (int)ulPinLen, pPin) < 0) ++ return CKR_DEVICE_MEMORY; + st_logf("type: %d password: %s\n", (int)userType, pin); + } + diff --git a/SOURCES/Fix-KCM-client-time-offset-propagation.patch b/SOURCES/Fix-KCM-client-time-offset-propagation.patch new file mode 100644 index 0000000..eedc4c0 --- /dev/null +++ b/SOURCES/Fix-KCM-client-time-offset-propagation.patch @@ -0,0 +1,33 @@ +From 7e4576cc62a16fa77030c42dcc43c61cdfa5b4e6 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 14 Aug 2019 13:52:27 -0400 +Subject: [PATCH] Fix KCM client time offset propagation + +An inverted status check in get_kdc_offset() would cause querying the +offset time from the ccache to always fail (silently) on KCM. Fix the +status check so that KCM can properly handle desync. + +ticket: 8826 (new) +tags: pullup +target_version: 1.17-next +target_verison: 1.16-next + +(cherry picked from commit 323abb6d1ebe5469d6c2167c29aa5d696d099b90) +(cherry picked from commit 7e81b8077cf2cf186dadb96b064573f7c221fbf3) +--- + src/lib/krb5/ccache/cc_kcm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c +index 092ab7daf..fe93ca3dc 100644 +--- a/src/lib/krb5/ccache/cc_kcm.c ++++ b/src/lib/krb5/ccache/cc_kcm.c +@@ -583,7 +583,7 @@ get_kdc_offset(krb5_context context, krb5_ccache cache) + if (cache_call(context, cache, &req, FALSE) != 0) + goto cleanup; + time_offset = k5_input_get_uint32_be(&req.reply); +- if (!req.reply.status) ++ if (req.reply.status) + goto cleanup; + context->os_context.time_offset = time_offset; + context->os_context.usec_offset = 0; diff --git a/SOURCES/Fix-argument-order-on-strlcpy-in-enctype_name.patch b/SOURCES/Fix-argument-order-on-strlcpy-in-enctype_name.patch index 9edc3ae..99648bd 100644 --- a/SOURCES/Fix-argument-order-on-strlcpy-in-enctype_name.patch +++ b/SOURCES/Fix-argument-order-on-strlcpy-in-enctype_name.patch @@ -1,4 +1,4 @@ -From 3a64eb3477e0e60d447c99f86b7bf4fd1259cb58 Mon Sep 17 00:00:00 2001 +From 9a38af6aa136fdc92d5e0f1591c1647aec498f5a Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Tue, 17 Sep 2019 18:29:15 -0400 Subject: [PATCH] Fix argument order on strlcpy() in enctype_name() diff --git a/SOURCES/Fix-memory-leak-in-none-replay-cache-type.patch b/SOURCES/Fix-memory-leak-in-none-replay-cache-type.patch index 22e5d59..166ef05 100644 --- a/SOURCES/Fix-memory-leak-in-none-replay-cache-type.patch +++ b/SOURCES/Fix-memory-leak-in-none-replay-cache-type.patch @@ -1,4 +1,4 @@ -From a904a5b85e8425823016b821153b37396edc2306 Mon Sep 17 00:00:00 2001 +From 74a3b8448949130d91417b261c3e1c316ffa8796 Mon Sep 17 00:00:00 2001 From: Corene Casper Date: Sat, 16 Feb 2019 00:49:26 -0500 Subject: [PATCH] Fix memory leak in 'none' replay cache type diff --git a/SOURCES/Fix-memory-leaks-in-soft-pkcs11-code.patch b/SOURCES/Fix-memory-leaks-in-soft-pkcs11-code.patch new file mode 100644 index 0000000..01e41fc --- /dev/null +++ b/SOURCES/Fix-memory-leaks-in-soft-pkcs11-code.patch @@ -0,0 +1,123 @@ +From 604f5dcbb018fca8ea27e00314ed615133b861e1 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 5 Aug 2019 01:53:51 -0400 +Subject: [PATCH] Fix memory leaks in soft-pkcs11 code + +Fix leaks detected by asan in t_pkinit.py. Add a helper to free a +struct st_object and free objects in C_Finalize(). Duplicate the X509 +cert in add_certificate() instead of creating aliases so it can be +properly freed. Start the session handle counter at 1 so that +C_Finalize() won't confuse the first session handle with +CK_INVALID_HANDLE (defined to 0 in pkinit.h) and will properly clean +the session object. + +(cherry picked from commit 15bcaf8bcb4af25ff89820ad3bf23ad5a324e863) +(cherry picked from commit 5cc80472e7a8b0fb3002f229ffb104dccf8bd120) +--- + src/tests/softpkcs11/main.c | 44 +++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c +index 2d1448ca2..a4c3ae78e 100644 +--- a/src/tests/softpkcs11/main.c ++++ b/src/tests/softpkcs11/main.c +@@ -109,7 +109,7 @@ struct st_object { + X509 *cert; + EVP_PKEY *public_key; + struct { +- const char *file; ++ char *file; + EVP_PKEY *key; + X509 *cert; + } private_key; +@@ -343,6 +343,26 @@ print_attributes(const CK_ATTRIBUTE *attributes, + } + } + ++static void ++free_st_object(struct st_object *o) ++{ ++ int i; ++ ++ for (i = 0; i < o->num_attributes; i++) ++ free(o->attrs[i].attribute.pValue); ++ free(o->attrs); ++ if (o->type == STO_T_CERTIFICATE) { ++ X509_free(o->u.cert); ++ } else if (o->type == STO_T_PRIVATE_KEY) { ++ free(o->u.private_key.file); ++ EVP_PKEY_free(o->u.private_key.key); ++ X509_free(o->u.private_key.cert); ++ } else if (o->type == STO_T_PUBLIC_KEY) { ++ EVP_PKEY_free(o->u.public_key); ++ } ++ free(o); ++} ++ + static struct st_object * + add_st_object(void) + { +@@ -518,7 +538,11 @@ add_certificate(char *label, + goto out; + } + o->type = STO_T_CERTIFICATE; +- o->u.cert = cert; ++ o->u.cert = X509_dup(cert); ++ if (o->u.cert == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } + public_key = X509_get_pubkey(o->u.cert); + + switch (EVP_PKEY_base_id(public_key)) { +@@ -602,7 +626,11 @@ add_certificate(char *label, + o->u.private_key.file = strdup(private_key_file); + o->u.private_key.key = NULL; + +- o->u.private_key.cert = cert; ++ o->u.private_key.cert = X509_dup(cert); ++ if (o->u.private_key.cert == NULL) { ++ ret = CKR_DEVICE_MEMORY; ++ goto out; ++ } + + c = CKO_PRIVATE_KEY; + add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c)); +@@ -676,6 +704,7 @@ add_certificate(char *label, + free(serial_data); + free(issuer_data); + free(subject_data); ++ X509_free(cert); + + return ret; + } +@@ -872,7 +901,7 @@ C_Initialize(CK_VOID_PTR a) + st_logf("\tFlags\t%04x\n", (unsigned int)args->flags); + } + +- soft_token.next_session_handle = 0; ++ soft_token.next_session_handle = 1; + + fn = get_rcfilename(); + if (fn == NULL) +@@ -886,6 +915,7 @@ CK_RV + C_Finalize(CK_VOID_PTR args) + { + size_t i; ++ int j; + + st_logf("Finalize\n"); + +@@ -897,6 +927,12 @@ C_Finalize(CK_VOID_PTR args) + } + } + ++ for (j = 0; j < soft_token.object.num_objs; j++) ++ free_st_object(soft_token.object.objs[j]); ++ free(soft_token.object.objs); ++ soft_token.object.objs = NULL; ++ soft_token.object.num_objs = 0; ++ + return CKR_OK; + } + diff --git a/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch b/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch deleted file mode 100644 index b2a4f87..0000000 --- a/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch +++ /dev/null @@ -1,354 +0,0 @@ -From 088fd5a56e030739a31a43aee7335bc661a92b1c Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Tue, 31 Jul 2018 13:47:26 -0400 -Subject: [PATCH] In FIPS mode, add plaintext fallback for RC4 usages and taint - -(cherry picked from commit a327e3bf5b992ac829c7b2d3317fb7d93b1c88ef) -(cherry picked from commit 2bd85da058d2d73eb2818a8e64656fec9b21b3c3) ---- - src/lib/krad/attr.c | 45 +++++++++++++++++++++++++++++----------- - src/lib/krad/attrset.c | 5 +++-- - src/lib/krad/internal.h | 13 ++++++++++-- - src/lib/krad/packet.c | 22 +++++++++++--------- - src/lib/krad/remote.c | 10 +++++++-- - src/lib/krad/t_attr.c | 3 ++- - src/lib/krad/t_attrset.c | 4 +++- - 7 files changed, 72 insertions(+), 30 deletions(-) - -diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c -index 9c13d9d75..275327e67 100644 ---- a/src/lib/krad/attr.c -+++ b/src/lib/krad/attr.c -@@ -30,6 +30,7 @@ - #include - #include "internal.h" - -+#include - #include - - /* RFC 2865 */ -@@ -38,7 +39,8 @@ - typedef krb5_error_code - (*attribute_transform_fn)(krb5_context ctx, const char *secret, - const unsigned char *auth, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *is_fips); - - typedef struct { - const char *name; -@@ -51,12 +53,14 @@ typedef struct { - static krb5_error_code - user_password_encode(krb5_context ctx, const char *secret, - const unsigned char *auth, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *is_fips); - - static krb5_error_code - user_password_decode(krb5_context ctx, const char *secret, - const unsigned char *auth, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *ignored); - - static const attribute_record attributes[UCHAR_MAX] = { - {"User-Name", 1, MAX_ATTRSIZE, NULL, NULL}, -@@ -128,7 +132,8 @@ static const attribute_record attributes[UCHAR_MAX] = { - static krb5_error_code - user_password_encode(krb5_context ctx, const char *secret, - const unsigned char *auth, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *is_fips) - { - const unsigned char *indx; - krb5_error_code retval; -@@ -154,8 +159,14 @@ user_password_encode(krb5_context ctx, const char *secret, - for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) { - memcpy(tmp.data + seclen, indx, BLOCKSIZE); - -- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp, -- &sum); -+ if (FIPS_mode()) { -+ /* Skip encryption here. Taint so that we won't pass it out of -+ * the machine by accident. */ -+ *is_fips = TRUE; -+ sum.contents = calloc(1, BLOCKSIZE); -+ } else -+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp, -+ &sum); - if (retval != 0) { - zap(tmp.data, tmp.length); - zap(outbuf, len); -@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret, - static krb5_error_code - user_password_decode(krb5_context ctx, const char *secret, - const unsigned char *auth, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *is_fips) - { - const unsigned char *indx; - krb5_error_code retval; -@@ -204,8 +216,14 @@ user_password_decode(krb5_context ctx, const char *secret, - for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) { - memcpy(tmp.data + seclen, indx, BLOCKSIZE); - -- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, -- &tmp, &sum); -+ if (FIPS_mode()) { -+ /* Skip encryption here. Taint so that we won't pass it out of -+ * the machine by accident. */ -+ *is_fips = TRUE; -+ sum.contents = calloc(1, BLOCKSIZE); -+ } else -+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, -+ &tmp, &sum); - if (retval != 0) { - zap(tmp.data, tmp.length); - zap(outbuf, in->length); -@@ -248,7 +266,7 @@ krb5_error_code - kr_attr_encode(krb5_context ctx, const char *secret, - const unsigned char *auth, krad_attr type, - const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE], -- size_t *outlen) -+ size_t *outlen, krb5_boolean *is_fips) - { - krb5_error_code retval; - -@@ -265,7 +283,8 @@ kr_attr_encode(krb5_context ctx, const char *secret, - return 0; - } - -- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen); -+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen, -+ is_fips); - } - - krb5_error_code -@@ -274,6 +293,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, - unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) - { - krb5_error_code retval; -+ krb5_boolean ignored; - - retval = kr_attr_valid(type, in); - if (retval != 0) -@@ -288,7 +308,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, - return 0; - } - -- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen); -+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen, -+ &ignored); - } - - krad_attr -diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c -index 03c613716..d89982a13 100644 ---- a/src/lib/krad/attrset.c -+++ b/src/lib/krad/attrset.c -@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy) - krb5_error_code - kr_attrset_encode(const krad_attrset *set, const char *secret, - const unsigned char *auth, -- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen) -+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, -+ krb5_boolean *is_fips) - { - unsigned char buffer[MAX_ATTRSIZE]; - krb5_error_code retval; -@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret, - - K5_TAILQ_FOREACH(a, &set->list, list) { - retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr, -- buffer, &attrlen); -+ buffer, &attrlen, is_fips); - if (retval != 0) - return retval; - -diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h -index 996a89372..a53ce31ce 100644 ---- a/src/lib/krad/internal.h -+++ b/src/lib/krad/internal.h -@@ -49,6 +49,13 @@ - - typedef struct krad_remote_st krad_remote; - -+struct krad_packet_st { -+ char buffer[KRAD_PACKET_SIZE_MAX]; -+ krad_attrset *attrset; -+ krb5_data pkt; -+ krb5_boolean is_fips; -+}; -+ - /* Validate constraints of an attribute. */ - krb5_error_code - kr_attr_valid(krad_attr type, const krb5_data *data); -@@ -57,7 +64,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data); - krb5_error_code - kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth, - krad_attr type, const krb5_data *in, -- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); -+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, -+ krb5_boolean *is_fips); - - /* Decode an attribute. */ - krb5_error_code -@@ -69,7 +77,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, - krb5_error_code - kr_attrset_encode(const krad_attrset *set, const char *secret, - const unsigned char *auth, -- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen); -+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, -+ krb5_boolean *is_fips); - - /* Decode attributes from a buffer. */ - krb5_error_code -diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c -index c597174b6..794ac84c4 100644 ---- a/src/lib/krad/packet.c -+++ b/src/lib/krad/packet.c -@@ -32,6 +32,7 @@ - #include - - #include -+#include - - typedef unsigned char uchar; - -@@ -53,12 +54,6 @@ typedef unsigned char uchar; - #define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH)) - #define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR)) - --struct krad_packet_st { -- char buffer[KRAD_PACKET_SIZE_MAX]; -- krad_attrset *attrset; -- krb5_data pkt; --}; -- - typedef struct { - uchar x[(UCHAR_MAX + 1) / 8]; - } idmap; -@@ -187,8 +182,13 @@ auth_generate_response(krb5_context ctx, const char *secret, - memcpy(data.data + response->pkt.length, secret, strlen(secret)); - - /* Hash it. */ -- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data, -- &hash); -+ if (FIPS_mode()) { -+ /* This checksum does very little security-wise anyway, so don't -+ * taint. */ -+ hash.contents = calloc(1, AUTH_FIELD_SIZE); -+ } else -+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data, -+ &hash); - free(data.data); - if (retval != 0) - return retval; -@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, - - /* Encode the attributes. */ - retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt), -- &attrset_len); -+ &attrset_len, &pkt->is_fips); - if (retval != 0) - goto error; - -@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, - - /* Encode the attributes. */ - retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt), -- &attrset_len); -+ &attrset_len, &pkt->is_fips); - if (retval != 0) - goto error; - -@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret, - const krb5_data * - krad_packet_encode(const krad_packet *pkt) - { -+ if (pkt->is_fips) -+ return NULL; - return &pkt->pkt; - } - -diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c -index 437f7e91a..0f90443ce 100644 ---- a/src/lib/krad/remote.c -+++ b/src/lib/krad/remote.c -@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr) - request *r; - - K5_TAILQ_FOREACH(r, &rr->list, list) { -- tmp = krad_packet_encode(r->request); -+ tmp = &r->request->pkt; - - /* If the packet has already been sent, do nothing. */ - if (r->sent == tmp->length) -@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr) - if (req != NULL) { - K5_TAILQ_FOREACH(r, &rr->list, list) { - if (r->request == req && -- r->sent == krad_packet_encode(req)->length) { -+ r->sent == req->pkt.length) { - request_finish(r, 0, rsp); - break; - } -@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs, - (krad_packet_iter_cb)iterator, &r, &tmp); - if (retval != 0) - goto error; -+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL && -+ rr->info->ai_family != AF_UNIX) { -+ /* This would expose cleartext passwords, so abort. */ -+ retval = ESOCKTNOSUPPORT; -+ goto error; -+ } - - K5_TAILQ_FOREACH(r, &rr->list, list) { - if (r->request == tmp) { -diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c -index eb2a780c8..4d285ad9d 100644 ---- a/src/lib/krad/t_attr.c -+++ b/src/lib/krad/t_attr.c -@@ -50,6 +50,7 @@ main() - const char *tmp; - krb5_data in; - size_t len; -+ krb5_boolean is_fips = FALSE; - - noerror(krb5_init_context(&ctx)); - -@@ -73,7 +74,7 @@ main() - in = string2data((char *)decoded); - retval = kr_attr_encode(ctx, secret, auth, - krad_attr_name2num("User-Password"), -- &in, outbuf, &len); -+ &in, outbuf, &len, &is_fips); - insist(retval == 0); - insist(len == sizeof(encoded)); - insist(memcmp(outbuf, encoded, len) == 0); -diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c -index 7928335ca..0f9576253 100644 ---- a/src/lib/krad/t_attrset.c -+++ b/src/lib/krad/t_attrset.c -@@ -49,6 +49,7 @@ main() - krb5_context ctx; - size_t len = 0, encode_len; - krb5_data tmp; -+ krb5_boolean is_fips = FALSE; - - noerror(krb5_init_context(&ctx)); - noerror(krad_attrset_new(ctx, &set)); -@@ -62,7 +63,8 @@ main() - noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp)); - - /* Encode attrset. */ -- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len)); -+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len, -+ &is_fips)); - krad_attrset_free(set); - - /* Manually encode User-Name. */ diff --git a/SOURCES/In-kpropd-debug-log-proper-ticket-enctype-names.patch b/SOURCES/In-kpropd-debug-log-proper-ticket-enctype-names.patch index 7c83389..8a20e3d 100644 --- a/SOURCES/In-kpropd-debug-log-proper-ticket-enctype-names.patch +++ b/SOURCES/In-kpropd-debug-log-proper-ticket-enctype-names.patch @@ -1,4 +1,4 @@ -From e07ddc519254a35e54af020643685b9da9e0e973 Mon Sep 17 00:00:00 2001 +From 30f112f8dc1c5241da5ba301cb45a06bb5bb4c01 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Tue, 15 Jan 2019 13:41:16 -0500 Subject: [PATCH] In kpropd, debug-log proper ticket enctype names diff --git a/SOURCES/In-rd_req_dec-always-log-non-permitted-enctypes.patch b/SOURCES/In-rd_req_dec-always-log-non-permitted-enctypes.patch index 51115f6..6ca3da0 100644 --- a/SOURCES/In-rd_req_dec-always-log-non-permitted-enctypes.patch +++ b/SOURCES/In-rd_req_dec-always-log-non-permitted-enctypes.patch @@ -1,4 +1,4 @@ -From 83c2f0bac35c2ad0872dc9b2a9ca1bdde948f216 Mon Sep 17 00:00:00 2001 +From 2b4521f3ba3dad064e3f64bfd56b88d5cb5d0955 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Mon, 14 Jan 2019 17:14:42 -0500 Subject: [PATCH] In rd_req_dec, always log non-permitted enctypes diff --git a/SOURCES/Make-etype-names-in-KDC-logs-human-readable.patch b/SOURCES/Make-etype-names-in-KDC-logs-human-readable.patch index b2e21f3..8b3413b 100644 --- a/SOURCES/Make-etype-names-in-KDC-logs-human-readable.patch +++ b/SOURCES/Make-etype-names-in-KDC-logs-human-readable.patch @@ -1,4 +1,4 @@ -From c3dd133cf06d55e3fe516a2aa8b4b37e203878da Mon Sep 17 00:00:00 2001 +From f815140182976e882445a38ee5a0a77f56da7c8a Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Tue, 8 Jan 2019 17:42:35 -0500 Subject: [PATCH] Make etype names in KDC logs human-readable @@ -12,9 +12,9 @@ ticket: 8772 (new) (cherry picked from commit a649279727490687d54becad91fde8cf7429d951) --- src/kdc/kdc_log.c | 42 +++++++-------- - src/kdc/kdc_util.c | 125 +++++++++++++++++++++++---------------------- + src/kdc/kdc_util.c | 131 +++++++++++++++++++++++---------------------- src/kdc/kdc_util.h | 6 +-- - 3 files changed, 87 insertions(+), 86 deletions(-) + 3 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c index 4eec50373..b160ba21a 100644 @@ -132,75 +132,40 @@ index 0155c28c6..f5c581c82 100644 - * L10_2 = log10(2**x), rounded up; log10(2) ~= 0.301. - */ -#define L10_2(x) ((int)(((x * 301) + 999) / 1000)) -+/* Wrapper of krb5_enctype_to_name() to include the PKINIT types. */ -+static krb5_error_code -+enctype_name(krb5_enctype ktype, char *buf, size_t buflen) -+{ -+ char *name; -+ -+ if (buflen == 0) -+ return EINVAL; -+ *buf = '\0'; /* ensure these are always valid C-strings */ -+ -+ /* rfc4556 recommends that clients wishing to indicate support for these -+ * pkinit algorithms include them in the etype field of the AS-REQ. */ -+ if (ktype == ENCTYPE_DSA_SHA1_CMS) -+ name = "id-dsa-with-sha1-CmsOID"; -+ else if (ktype == ENCTYPE_MD5_RSA_CMS) -+ name = "md5WithRSAEncryption-CmsOID"; -+ else if (ktype == ENCTYPE_SHA1_RSA_CMS) -+ name = "sha-1WithRSAEncryption-CmsOID"; -+ else if (ktype == ENCTYPE_RC2_CBC_ENV) -+ name = "rc2-cbc-EnvOID"; -+ else if (ktype == ENCTYPE_RSA_ENV) -+ name = "rsaEncryption-EnvOID"; -+ else if (ktype == ENCTYPE_RSA_ES_OAEP_ENV) -+ name = "id-RSAES-OAEP-EnvOID"; -+ else if (ktype == ENCTYPE_DES3_CBC_ENV) -+ name = "des-ede3-cbc-EnvOID"; -+ else -+ return krb5_enctype_to_name(ktype, FALSE, buf, buflen); - +- -/* - * Max length of sprintf("%ld") for an int of type T; includes leading - * minus sign and terminating NUL. - */ -#define D_LEN(t) (L10_2(sizeof(t) * CHAR_BIT) + 2) -+ if (strlcpy(name, buf, buflen) >= buflen) -+ return ENOMEM; -+ return 0; -+} - +- -void -ktypes2str(char *s, size_t len, int nktypes, krb5_enctype *ktype) -+char * -+ktypes2str(krb5_enctype *ktype, int nktypes) ++/* Wrapper of krb5_enctype_to_name() to include the PKINIT types. */ ++static krb5_error_code ++enctype_name(krb5_enctype ktype, char *buf, size_t buflen) { -+ struct k5buf buf; - int i; +- int i; - char stmp[D_LEN(krb5_enctype) + 1]; - char *p; -+ char name[64]; ++ char *name; - if (nktypes < 0 - || len < (sizeof(" etypes {...}") + D_LEN(int))) { - *s = '\0'; - return; - } -+ if (nktypes < 0) -+ return NULL; ++ if (buflen == 0) ++ return EINVAL; ++ *buf = '\0'; /* ensure these are always valid C-strings */ - snprintf(s, len, "%d etypes {", nktypes); -+ k5_buf_init_dynamic(&buf); -+ k5_buf_add_fmt(&buf, "%d etypes {", nktypes); - for (i = 0; i < nktypes; i++) { +- for (i = 0; i < nktypes; i++) { - snprintf(stmp, sizeof(stmp), "%s%ld", i ? " " : "", (long)ktype[i]); - if (strlen(s) + strlen(stmp) + sizeof("}") > len) - break; - strlcat(s, stmp, len); -+ enctype_name(ktype[i], name, sizeof(name)); -+ k5_buf_add_fmt(&buf, "%s%s(%ld)", i ? ", " : "", name, (long)ktype[i]); - } +- } - if (i < nktypes) { - /* - * We broke out of the loop. Try to truncate the list. @@ -218,27 +183,65 @@ index 0155c28c6..f5c581c82 100644 - } - strlcat(s, "}", len); - return; -+ k5_buf_add(&buf, "}"); -+ return buf.data; ++ /* rfc4556 recommends that clients wishing to indicate support for these ++ * pkinit algorithms include them in the etype field of the AS-REQ. */ ++ if (ktype == ENCTYPE_DSA_SHA1_CMS) ++ name = "id-dsa-with-sha1-CmsOID"; ++ else if (ktype == ENCTYPE_MD5_RSA_CMS) ++ name = "md5WithRSAEncryption-CmsOID"; ++ else if (ktype == ENCTYPE_SHA1_RSA_CMS) ++ name = "sha-1WithRSAEncryption-CmsOID"; ++ else if (ktype == ENCTYPE_RC2_CBC_ENV) ++ name = "rc2-cbc-EnvOID"; ++ else if (ktype == ENCTYPE_RSA_ENV) ++ name = "rsaEncryption-EnvOID"; ++ else if (ktype == ENCTYPE_RSA_ES_OAEP_ENV) ++ name = "id-RSAES-OAEP-EnvOID"; ++ else if (ktype == ENCTYPE_DES3_CBC_ENV) ++ name = "des-ede3-cbc-EnvOID"; ++ else ++ return krb5_enctype_to_name(ktype, FALSE, buf, buflen); ++ ++ if (strlcpy(name, buf, buflen) >= buflen) ++ return ENOMEM; ++ return 0; } -void -rep_etypes2str(char *s, size_t len, krb5_kdc_rep *rep) +char * -+rep_etypes2str(krb5_kdc_rep *rep) ++ktypes2str(krb5_enctype *ktype, int nktypes) { - char stmp[sizeof("ses=") + D_LEN(krb5_enctype)]; -- ++ struct k5buf buf; ++ int i; ++ char name[64]; + - if (len < (3 * D_LEN(krb5_enctype) - + sizeof("etypes {rep= tkt= ses=}"))) { - *s = '\0'; - return; -- } ++ if (nktypes < 0) ++ return NULL; ++ ++ k5_buf_init_dynamic(&buf); ++ k5_buf_add_fmt(&buf, "%d etypes {", nktypes); ++ for (i = 0; i < nktypes; i++) { ++ enctype_name(ktype[i], name, sizeof(name)); ++ k5_buf_add_fmt(&buf, "%s%s(%ld)", i ? ", " : "", name, (long)ktype[i]); + } ++ k5_buf_add(&buf, "}"); ++ return buf.data; ++} + +- snprintf(s, len, "etypes {rep=%ld", (long)rep->enc_part.enctype); ++char * ++rep_etypes2str(krb5_kdc_rep *rep) ++{ + struct k5buf buf; + char name[64]; + krb5_enctype etype; - -- snprintf(s, len, "etypes {rep=%ld", (long)rep->enc_part.enctype); ++ + k5_buf_init_dynamic(&buf); + k5_buf_add(&buf, "etypes {rep="); + enctype_name(rep->enc_part.enctype, name, sizeof(name)); diff --git a/SOURCES/Mark-deprecated-enctypes-when-used.patch b/SOURCES/Mark-deprecated-enctypes-when-used.patch index c638cce..4ded20a 100644 --- a/SOURCES/Mark-deprecated-enctypes-when-used.patch +++ b/SOURCES/Mark-deprecated-enctypes-when-used.patch @@ -1,4 +1,4 @@ -From 4f56267a204764ed3d00e69cd16a0e877f055455 Mon Sep 17 00:00:00 2001 +From 6306a2a8697c94f968a02d66204f7d357aa0e7f6 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Thu, 10 Jan 2019 16:34:54 -0500 Subject: [PATCH] Mark deprecated enctypes when used diff --git a/SOURCES/Properly-size-ifdef-in-k5_cccol_lock.patch b/SOURCES/Properly-size-ifdef-in-k5_cccol_lock.patch index 001ef5a..b1e4563 100644 --- a/SOURCES/Properly-size-ifdef-in-k5_cccol_lock.patch +++ b/SOURCES/Properly-size-ifdef-in-k5_cccol_lock.patch @@ -1,4 +1,4 @@ -From 11ebf658c737baddcd5ce91e018213f28c279737 Mon Sep 17 00:00:00 2001 +From bad6d4390e6e23099cc2295d94e2553575687561 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Thu, 14 Feb 2019 11:50:35 -0500 Subject: [PATCH] Properly size #ifdef in k5_cccol_lock() diff --git a/SOURCES/Put-KDB-authdata-first.patch b/SOURCES/Put-KDB-authdata-first.patch new file mode 100644 index 0000000..998fa0e --- /dev/null +++ b/SOURCES/Put-KDB-authdata-first.patch @@ -0,0 +1,45 @@ +From 684821fc68fd27ddcc5f809a37819edd35365a9d Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Sat, 1 Feb 2020 16:13:30 +0100 +Subject: [PATCH] Put KDB authdata first + +Windows services, as well as some versions of Samba, may refuse +tickets if the PAC is not in the first AD-IF-RELEVANT container. In +fetch_kdb_authdata(), change the merge order so that authdata from the +KDB module appears first. + +[ghudson@mit.edu: added comment and clarified commit message] + +ticket: 8872 (new) +tags: pullup +target_version: 1.18 +target_version: 1.17-next + +(cherry picked from commit 331fa4bdd34263ea20667a0f51338cb84357fdaa) +(cherry picked from commit 1678270de3fda699114122447b1f06b08fb4e53e) +--- + src/kdc/kdc_authdata.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c +index 1b067cb0b..616c3eadc 100644 +--- a/src/kdc/kdc_authdata.c ++++ b/src/kdc/kdc_authdata.c +@@ -383,11 +383,14 @@ fetch_kdb_authdata(krb5_context context, unsigned int flags, + if (ret) + return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret; + +- /* Add the KDB authdata to the ticket, without copying or filtering. */ +- ret = merge_authdata(context, db_authdata, +- &enc_tkt_reply->authorization_data, FALSE, FALSE); ++ /* Put the KDB authdata first in the ticket. A successful merge places the ++ * combined list in db_authdata and releases the old ticket authdata. */ ++ ret = merge_authdata(context, enc_tkt_reply->authorization_data, ++ &db_authdata, FALSE, FALSE); + if (ret) + krb5_free_authdata(context, db_authdata); ++ else ++ enc_tkt_reply->authorization_data = db_authdata; + return ret; + } + diff --git a/SOURCES/Use-backported-version-of-OpenSSL-3-KDF-interface.patch b/SOURCES/Use-backported-version-of-OpenSSL-3-KDF-interface.patch new file mode 100644 index 0000000..b8d3916 --- /dev/null +++ b/SOURCES/Use-backported-version-of-OpenSSL-3-KDF-interface.patch @@ -0,0 +1,751 @@ +From 5e147f7f2924edfd278940dea8b1d8ed09d6872c Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Nov 2019 20:05:16 +0000 +Subject: [PATCH] Use backported version of OpenSSL-3 KDF interface + +(cherry picked from commit 0e20daf7ccfe50518c89735c3dae2fde08d92325) +--- + src/configure.in | 4 + + src/lib/crypto/krb/derive.c | 356 +++++++++++++----- + .../preauth/pkinit/pkinit_crypto_openssl.c | 257 ++++++++----- + 3 files changed, 428 insertions(+), 189 deletions(-) + +diff --git a/src/configure.in b/src/configure.in +index 9f6b67b44..cf4b1139a 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -269,6 +269,10 @@ AC_SUBST(CRYPTO_IMPL) + AC_SUBST(CRYPTO_IMPL_CFLAGS) + AC_SUBST(CRYPTO_IMPL_LIBS) + ++AC_CHECK_FUNCS(EVP_KDF_CTX_new_id EVP_KDF_ctrl EVP_KDF_derive, ++ AC_DEFINE(OSSL_KDFS, 1, [Define if using OpenSSL KDFs]), ++ AC_MSG_ERROR([backported OpenSSL KDFs not found])) ++ + AC_ARG_WITH([prng-alg], + AC_HELP_STRING([--with-prng-alg=ALG], [use specified PRNG algorithm. @<:@fortuna@:>@]), + [PRNG_ALG=$withval +diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c +index 6707a7308..915a173dd 100644 +--- a/src/lib/crypto/krb/derive.c ++++ b/src/lib/crypto/krb/derive.c +@@ -27,6 +27,13 @@ + + #include "crypto_int.h" + ++#ifdef OSSL_KDFS ++#include ++#include ++#else ++#error "Refusing to build without OpenSSL KDFs!" ++#endif ++ + static krb5_key + find_cached_dkey(struct derived_key *list, const krb5_data *constant) + { +@@ -77,55 +84,193 @@ cleanup: + return ENOMEM; + } + ++#ifdef OSSL_KDFS + static krb5_error_code +-derive_random_rfc3961(const struct krb5_enc_provider *enc, +- krb5_key inkey, krb5_data *outrnd, +- const krb5_data *in_constant) ++openssl_kbdkf_counter_hmac(const struct krb5_hash_provider *hash, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *label, const krb5_data *context) + { +- size_t blocksize, keybytes, n; ++ krb5_error_code ret = KRB5_CRYPTO_INTERNAL; ++ EVP_KDF_CTX *ctx = NULL; ++ const EVP_MD *digest; ++ ++ if (!strcmp(hash->hash_name, "SHA1")) ++ digest = EVP_sha1(); ++ else if (!strcmp(hash->hash_name, "SHA-256")) ++ digest = EVP_sha256(); ++ else if (!strcmp(hash->hash_name, "SHA-384")) ++ digest = EVP_sha384(); ++ else ++ goto done; ++ ++ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB); ++ if (!ctx) ++ goto done; ++ ++ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, ++ EVP_KDF_KB_MAC_TYPE_HMAC) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents, ++ inkey->keyblock.length) != 1 || ++ (context->length > 0 && ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_INFO, context->data, ++ context->length) != 1) || ++ (label->length > 0 && ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, label->data, ++ label->length) != 1) || ++ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data, ++ outrnd->length) != 1) ++ goto done; ++ ++ ret = 0; ++done: ++ if (ret) ++ zap(outrnd->data, outrnd->length); ++ EVP_KDF_CTX_free(ctx); ++ return ret; ++} ++ ++static krb5_error_code ++openssl_kbkdf_feedback_cmac(const struct krb5_enc_provider *enc, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *in_constant) ++{ ++ krb5_error_code ret = KRB5_CRYPTO_INTERNAL; ++ EVP_KDF_CTX *ctx = NULL; ++ const EVP_CIPHER *cipher; ++ static unsigned char zeroes[16]; ++ ++ memset(zeroes, 0, sizeof(zeroes)); ++ ++ if (enc->keylength == 16) ++ cipher = EVP_camellia_128_cbc(); ++ else if (enc->keylength == 32) ++ cipher = EVP_camellia_256_cbc(); ++ else ++ goto done; ++ ++ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB); ++ if (!ctx) ++ goto done; ++ ++ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MODE, ++ EVP_KDF_KB_MODE_FEEDBACK) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, ++ EVP_KDF_KB_MAC_TYPE_CMAC) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents, ++ inkey->keyblock.length) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, in_constant->data, ++ in_constant->length) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_SEED, zeroes, ++ sizeof(zeroes)) != 1 || ++ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data, ++ outrnd->length) != 1) ++ goto done; ++ ++ ret = 0; ++done: ++ if (ret) ++ zap(outrnd->data, outrnd->length); ++ EVP_KDF_CTX_free(ctx); ++ return ret; ++} ++ ++static krb5_error_code ++openssl_krb5kdf(const struct krb5_enc_provider *enc, krb5_key inkey, ++ krb5_data *outrnd, const krb5_data *in_constant) ++{ ++ krb5_error_code ret = KRB5_CRYPTO_INTERNAL; ++ EVP_KDF_CTX *ctx = NULL; ++ const EVP_CIPHER *cipher; ++ ++ if (inkey->keyblock.length != enc->keylength || ++ outrnd->length != enc->keybytes) { ++ return KRB5_CRYPTO_INTERNAL; ++ } ++ ++ if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 16) ++ cipher = EVP_aes_128_cbc(); ++ else if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 32) ++ cipher = EVP_aes_256_cbc(); ++ else if (enc->keylength == 24) ++ cipher = EVP_des_ede3_cbc(); ++ else ++ goto done; ++ ++ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF); ++ if (ctx == NULL) ++ goto done; ++ ++ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents, ++ inkey->keyblock.length) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT, ++ in_constant->data, in_constant->length) != 1 || ++ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data, ++ outrnd->length) != 1) ++ goto done; ++ ++ ret = 0; ++done: ++ if (ret) ++ zap(outrnd->data, outrnd->length); ++ EVP_KDF_CTX_free(ctx); ++ return ret; ++} ++ ++#else /* OSSL_KDFS */ ++ ++/* ++ * NIST SP800-108 KDF in counter mode (section 5.1). ++ * Parameters: ++ * - HMAC (with hash as the hash provider) is the PRF. ++ * - A block counter of four bytes is used. ++ * - Four bytes are used to encode the output length in the PRF input. ++ * ++ * There are no uses requiring more than a single PRF invocation. ++ */ ++static krb5_error_code ++builtin_sp800_108_counter_hmac(const struct krb5_hash_provider *hash, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *label, ++ const krb5_data *context) ++{ ++ krb5_crypto_iov iov[5]; + krb5_error_code ret; +- krb5_data block = empty_data(); ++ krb5_data prf; ++ unsigned char ibuf[4], lbuf[4]; + +- blocksize = enc->block_size; +- keybytes = enc->keybytes; +- +- if (blocksize == 1) +- return KRB5_BAD_ENCTYPE; +- if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes) ++ if (hash == NULL || outrnd->length > hash->hashsize) + return KRB5_CRYPTO_INTERNAL; + + /* Allocate encryption data buffer. */ +- ret = alloc_data(&block, blocksize); ++ ret = alloc_data(&prf, hash->hashsize); + if (ret) + return ret; + +- /* Initialize the input block. */ +- if (in_constant->length == blocksize) { +- memcpy(block.data, in_constant->data, blocksize); +- } else { +- krb5int_nfold(in_constant->length * 8, +- (unsigned char *) in_constant->data, +- blocksize * 8, (unsigned char *) block.data); +- } ++ /* [i]2: four-byte big-endian binary string giving the block counter (1) */ ++ iov[0].flags = KRB5_CRYPTO_TYPE_DATA; ++ iov[0].data = make_data(ibuf, sizeof(ibuf)); ++ store_32_be(1, ibuf); ++ /* Label */ ++ iov[1].flags = KRB5_CRYPTO_TYPE_DATA; ++ iov[1].data = *label; ++ /* 0x00: separator byte */ ++ iov[2].flags = KRB5_CRYPTO_TYPE_DATA; ++ iov[2].data = make_data("", 1); ++ /* Context */ ++ iov[3].flags = KRB5_CRYPTO_TYPE_DATA; ++ iov[3].data = *context; ++ /* [L]2: four-byte big-endian binary string giving the output length */ ++ iov[4].flags = KRB5_CRYPTO_TYPE_DATA; ++ iov[4].data = make_data(lbuf, sizeof(lbuf)); ++ store_32_be(outrnd->length * 8, lbuf); + +- /* Loop encrypting the blocks until enough key bytes are generated. */ +- n = 0; +- while (n < keybytes) { +- ret = encrypt_block(enc, inkey, &block); +- if (ret) +- goto cleanup; +- +- if ((keybytes - n) <= blocksize) { +- memcpy(outrnd->data + n, block.data, (keybytes - n)); +- break; +- } +- +- memcpy(outrnd->data + n, block.data, blocksize); +- n += blocksize; +- } +- +-cleanup: +- zapfree(block.data, blocksize); ++ ret = krb5int_hmac(hash, inkey, iov, 5, &prf); ++ if (!ret) ++ memcpy(outrnd->data, prf.data, outrnd->length); ++ zapfree(prf.data, prf.length); + return ret; + } + +@@ -139,9 +284,9 @@ cleanup: + * - Four bytes are used to encode the output length in the PRF input. + */ + static krb5_error_code +-derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc, +- krb5_key inkey, krb5_data *outrnd, +- const krb5_data *in_constant) ++builtin_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *in_constant) + { + size_t blocksize, keybytes, n; + krb5_crypto_iov iov[6]; +@@ -204,56 +349,94 @@ cleanup: + return ret; + } + +-/* +- * NIST SP800-108 KDF in counter mode (section 5.1). +- * Parameters: +- * - HMAC (with hash as the hash provider) is the PRF. +- * - A block counter of four bytes is used. +- * - Four bytes are used to encode the output length in the PRF input. +- * +- * There are no uses requiring more than a single PRF invocation. +- */ ++static krb5_error_code ++builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *in_constant) ++{ ++ size_t blocksize, keybytes, n; ++ krb5_error_code ret; ++ krb5_data block = empty_data(); ++ ++ blocksize = enc->block_size; ++ keybytes = enc->keybytes; ++ ++ if (blocksize == 1) ++ return KRB5_BAD_ENCTYPE; ++ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes) ++ return KRB5_CRYPTO_INTERNAL; ++ ++ /* Allocate encryption data buffer. */ ++ ret = alloc_data(&block, blocksize); ++ if (ret) ++ return ret; ++ ++ /* Initialize the input block. */ ++ if (in_constant->length == blocksize) { ++ memcpy(block.data, in_constant->data, blocksize); ++ } else { ++ krb5int_nfold(in_constant->length * 8, ++ (unsigned char *) in_constant->data, ++ blocksize * 8, (unsigned char *) block.data); ++ } ++ ++ /* Loop encrypting the blocks until enough key bytes are generated. */ ++ n = 0; ++ while (n < keybytes) { ++ ret = encrypt_block(enc, inkey, &block); ++ if (ret) ++ goto cleanup; ++ ++ if ((keybytes - n) <= blocksize) { ++ memcpy(outrnd->data + n, block.data, (keybytes - n)); ++ break; ++ } ++ ++ memcpy(outrnd->data + n, block.data, blocksize); ++ n += blocksize; ++ } ++ ++cleanup: ++ zapfree(block.data, blocksize); ++ return ret; ++} ++#endif /* OSSL_KDFS */ ++ + krb5_error_code + k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash, + krb5_key inkey, krb5_data *outrnd, + const krb5_data *label, const krb5_data *context) + { +- krb5_crypto_iov iov[5]; +- krb5_error_code ret; +- krb5_data prf; +- unsigned char ibuf[4], lbuf[4]; ++#ifdef OSSL_KDFS ++ return openssl_kbdkf_counter_hmac(hash, inkey, outrnd, label, context); ++#else ++ return builtin_sp800_108_counter_hmac(hash, inkey, outrnd, label, ++ context); ++#endif ++} + +- if (hash == NULL || outrnd->length > hash->hashsize) +- return KRB5_CRYPTO_INTERNAL; ++static krb5_error_code ++k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *in_constant) ++{ ++#ifdef OSSL_KDFS ++ return openssl_kbkdf_feedback_cmac(enc, inkey, outrnd, in_constant); ++#else ++ return builtin_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant); ++#endif ++} + +- /* Allocate encryption data buffer. */ +- ret = alloc_data(&prf, hash->hashsize); +- if (ret) +- return ret; +- +- /* [i]2: four-byte big-endian binary string giving the block counter (1) */ +- iov[0].flags = KRB5_CRYPTO_TYPE_DATA; +- iov[0].data = make_data(ibuf, sizeof(ibuf)); +- store_32_be(1, ibuf); +- /* Label */ +- iov[1].flags = KRB5_CRYPTO_TYPE_DATA; +- iov[1].data = *label; +- /* 0x00: separator byte */ +- iov[2].flags = KRB5_CRYPTO_TYPE_DATA; +- iov[2].data = make_data("", 1); +- /* Context */ +- iov[3].flags = KRB5_CRYPTO_TYPE_DATA; +- iov[3].data = *context; +- /* [L]2: four-byte big-endian binary string giving the output length */ +- iov[4].flags = KRB5_CRYPTO_TYPE_DATA; +- iov[4].data = make_data(lbuf, sizeof(lbuf)); +- store_32_be(outrnd->length * 8, lbuf); +- +- ret = krb5int_hmac(hash, inkey, iov, 5, &prf); +- if (!ret) +- memcpy(outrnd->data, prf.data, outrnd->length); +- zapfree(prf.data, prf.length); +- return ret; ++static krb5_error_code ++k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, ++ krb5_key inkey, krb5_data *outrnd, ++ const krb5_data *in_constant) ++{ ++#ifdef OSSL_KDFS ++ return openssl_krb5kdf(enc, inkey, outrnd, in_constant); ++#else ++ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant); ++#endif + } + + krb5_error_code +@@ -266,10 +449,9 @@ krb5int_derive_random(const struct krb5_enc_provider *enc, + + switch (alg) { + case DERIVE_RFC3961: +- return derive_random_rfc3961(enc, inkey, outrnd, in_constant); ++ return k5_derive_random_rfc3961(enc, inkey, outrnd, in_constant); + case DERIVE_SP800_108_CMAC: +- return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd, +- in_constant); ++ return k5_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant); + case DERIVE_SP800_108_HMAC: + return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant, + &empty); +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 5ff81d8cf..8d2c230c8 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -38,6 +38,13 @@ + #include + #include + ++#ifdef OSSL_KDFS ++#include ++#include ++#else ++#error "Refusing to build without OpenSSL KDFs!" ++#endif ++ + static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context ); + static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ); + +@@ -2460,11 +2467,51 @@ pkinit_alg_values(krb5_context context, + } + } /* pkinit_alg_values() */ + ++#ifdef OSSL_KDFS ++static krb5_error_code ++openssl_sskdf(krb5_context context, size_t hash_bytes, krb5_data *key, ++ krb5_data *info, char *out, size_t out_len) ++{ ++ krb5_error_code ret = KRB5_CRYPTO_INTERNAL; ++ EVP_KDF_CTX *ctx = NULL; ++ const EVP_MD *digest; + +-/* pkinit_alg_agility_kdf() -- +- * This function generates a key using the KDF described in +- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is +- * described as follows: ++ /* RFC 8636 defines a SHA384 variant, but we don't use it. */ ++ if (hash_bytes == 20) { ++ digest = EVP_sha1(); ++ } else if (hash_bytes == 32) { ++ digest = EVP_sha256(); ++ } else if (hash_bytes == 64) { ++ digest = EVP_sha512(); ++ } else { ++ krb5_set_error_message(context, ret, "Bad hash type for SSKDF"); ++ goto done; ++ } ++ ++ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SS); ++ if (!ctx) { ++ oerr(context, ret, _("Failed to instantiate SSKDF")); ++ goto done; ++ } ++ ++ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key->data, ++ key->length) != 1 || ++ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSKDF_INFO, info->data, ++ info->length) != 1 || ++ EVP_KDF_derive(ctx, (unsigned char *)out, out_len) != 1) ++ goto done; ++ ++ ret = 0; ++done: ++ EVP_KDF_CTX_free(ctx); ++ return ret; ++} ++#else ++/* ++ * Generate a key using the KDF described in RFC 8636, also known as SSKDF ++ * (single-step kdf). Our caller precomputes `reps`, but otherwise the ++ * algorithm is as follows: + * + * 1. reps = keydatalen (K) / hash length (H) + * +@@ -2478,95 +2525,16 @@ pkinit_alg_values(krb5_context context, + * + * 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. + */ +-krb5_error_code +-pkinit_alg_agility_kdf(krb5_context context, +- krb5_data *secret, +- krb5_data *alg_oid, +- krb5_const_principal party_u_info, +- krb5_const_principal party_v_info, +- krb5_enctype enctype, +- krb5_data *as_req, +- krb5_data *pk_as_rep, +- krb5_keyblock *key_block) ++static krb5_error_code ++builtin_sskdf(krb5_context context, unsigned int reps, size_t hash_len, ++ const EVP_MD *(*EVP_func)(void), krb5_data *secret, ++ krb5_data *other_info, char *out, size_t out_len) + { + krb5_error_code retval = 0; + +- unsigned int reps = 0; +- uint32_t counter = 1; /* Does this type work on Windows? */ ++ uint32_t counter = 1; + size_t offset = 0; +- size_t hash_len = 0; +- size_t rand_len = 0; +- size_t key_len = 0; +- krb5_data random_data; +- krb5_sp80056a_other_info other_info_fields; +- krb5_pkinit_supp_pub_info supp_pub_info_fields; +- krb5_data *other_info = NULL; +- krb5_data *supp_pub_info = NULL; +- krb5_algorithm_identifier alg_id; + EVP_MD_CTX *ctx = NULL; +- const EVP_MD *(*EVP_func)(void); +- +- /* initialize random_data here to make clean-up safe */ +- random_data.length = 0; +- random_data.data = NULL; +- +- /* allocate and initialize the key block */ +- key_block->magic = 0; +- key_block->enctype = enctype; +- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len, +- &key_len))) +- goto cleanup; +- +- random_data.length = rand_len; +- key_block->length = key_len; +- +- if (NULL == (key_block->contents = malloc(key_block->length))) { +- retval = ENOMEM; +- goto cleanup; +- } +- +- memset (key_block->contents, 0, key_block->length); +- +- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */ +- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info, +- krb5_anonymous_principal())) +- party_u_info = (krb5_principal)krb5_anonymous_principal(); +- +- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func))) +- goto cleanup; +- +- /* 1. reps = keydatalen (K) / hash length (H) */ +- reps = key_block->length/hash_len; +- +- /* ... and round up, if necessary */ +- if (key_block->length > (reps * hash_len)) +- reps++; +- +- /* Allocate enough space in the random data buffer to hash directly into +- * it, even if the last hash will make it bigger than the key length. */ +- if (NULL == (random_data.data = malloc(reps * hash_len))) { +- retval = ENOMEM; +- goto cleanup; +- } +- +- /* Encode the ASN.1 octet string for "SuppPubInfo" */ +- supp_pub_info_fields.enctype = enctype; +- supp_pub_info_fields.as_req = *as_req; +- supp_pub_info_fields.pk_as_rep = *pk_as_rep; +- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields, +- &supp_pub_info)))) +- goto cleanup; +- +- /* Now encode the ASN.1 octet string for "OtherInfo" */ +- memset(&alg_id, 0, sizeof alg_id); +- alg_id.algorithm = *alg_oid; /*alias*/ +- +- other_info_fields.algorithm_identifier = alg_id; +- other_info_fields.party_u_info = (krb5_principal) party_u_info; +- other_info_fields.party_v_info = (krb5_principal) party_v_info; +- other_info_fields.supp_pub_info = *supp_pub_info; +- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info))) +- goto cleanup; + + /* 2. Initialize a 32-bit, big-endian bit string counter as 1. + * 3. For i = 1 to reps by 1, do the following: +@@ -2600,8 +2568,9 @@ pkinit_alg_agility_kdf(krb5_context context, + goto cleanup; + } + +- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */ +- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) { ++ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K ++ * bytes. */ ++ if (!EVP_DigestFinal(ctx, (unsigned char *)out + offset, &s)) { + krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL, + "Call to OpenSSL EVP_DigestUpdate() returned an error."); + retval = KRB5_CRYPTO_INTERNAL; +@@ -2613,26 +2582,110 @@ pkinit_alg_agility_kdf(krb5_context context, + EVP_MD_CTX_free(ctx); + ctx = NULL; + } +- +- retval = krb5_c_random_to_key(context, enctype, &random_data, +- key_block); +- + cleanup: + EVP_MD_CTX_free(ctx); ++ return retval; ++} /* builtin_sskdf() */ ++#endif /* OSSL_KDFS */ + +- /* If this has been an error, free the allocated key_block, if any */ +- if (retval) { +- krb5_free_keyblock_contents(context, key_block); ++/* id-pkinit-kdf family, as specified by RFC 8636. */ ++krb5_error_code ++pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret, ++ krb5_data *alg_oid, krb5_const_principal party_u_info, ++ krb5_const_principal party_v_info, ++ krb5_enctype enctype, krb5_data *as_req, ++ krb5_data *pk_as_rep, krb5_keyblock *key_block) ++{ ++ krb5_error_code retval; ++ size_t hash_len = 0, rand_len = 0, key_len = 0; ++ const EVP_MD *(*EVP_func)(void); ++ krb5_sp80056a_other_info other_info_fields; ++ krb5_pkinit_supp_pub_info supp_pub_info_fields; ++ krb5_data *other_info = NULL, *supp_pub_info = NULL; ++ krb5_data random_data = empty_data(); ++ krb5_algorithm_identifier alg_id; ++ unsigned int reps; ++ ++ /* Allocate and initialize the key block. */ ++ key_block->magic = 0; ++ key_block->enctype = enctype; ++ ++ /* Use separate variables to avoid alignment restriction problems. */ ++ retval = krb5_c_keylengths(context, enctype, &rand_len, &key_len); ++ if (retval) ++ goto cleanup; ++ random_data.length = rand_len; ++ key_block->length = key_len; ++ ++ key_block->contents = k5calloc(key_block->length, 1, &retval); ++ if (key_block->contents == NULL) ++ goto cleanup; ++ ++ /* If this is anonymous pkinit, use the anonymous principle for ++ * party_u_info. */ ++ if (party_u_info && ++ krb5_principal_compare_any_realm(context, party_u_info, ++ krb5_anonymous_principal())) { ++ party_u_info = (krb5_principal)krb5_anonymous_principal(); + } + +- /* free other allocated resources, either way */ +- if (random_data.data) +- free(random_data.data); ++ retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func); ++ if (retval) ++ goto cleanup; ++ ++ /* 1. reps = keydatalen (K) / hash length (H) */ ++ reps = key_block->length / hash_len; ++ ++ /* ... and round up, if necessary. */ ++ if (key_block->length > (reps * hash_len)) ++ reps++; ++ ++ /* Allocate enough space in the random data buffer to hash directly into ++ * it, even if the last hash will make it bigger than the key length. */ ++ random_data.data = k5alloc(reps * hash_len, &retval); ++ if (random_data.data == NULL) ++ goto cleanup; ++ ++ /* Encode the ASN.1 octet string for "SuppPubInfo". */ ++ supp_pub_info_fields.enctype = enctype; ++ supp_pub_info_fields.as_req = *as_req; ++ supp_pub_info_fields.pk_as_rep = *pk_as_rep; ++ retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields, ++ &supp_pub_info); ++ if (retval) ++ goto cleanup; ++ ++ /* Now encode the ASN.1 octet string for "OtherInfo". */ ++ memset(&alg_id, 0, sizeof(alg_id)); ++ alg_id.algorithm = *alg_oid; ++ other_info_fields.algorithm_identifier = alg_id; ++ other_info_fields.party_u_info = (krb5_principal)party_u_info; ++ other_info_fields.party_v_info = (krb5_principal)party_v_info; ++ other_info_fields.supp_pub_info = *supp_pub_info; ++ retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info); ++ if (retval) ++ goto cleanup; ++ ++#ifdef OSSL_KDFS ++ retval = openssl_sskdf(context, hash_len, secret, other_info, ++ random_data.data, key_block->length); ++#else ++ retval = builtin_sskdf(context, reps, hash_len, EVP_func, secret, ++ other_info, random_data.data, key_block->length); ++#endif ++ if (retval) ++ goto cleanup; ++ ++ retval = krb5_c_random_to_key(context, enctype, &random_data, key_block); ++cleanup: ++ if (retval) ++ krb5_free_keyblock_contents(context, key_block); ++ ++ zapfree(random_data.data, random_data.length); + krb5_free_data(context, other_info); + krb5_free_data(context, supp_pub_info); +- + return retval; +-} /*pkinit_alg_agility_kdf() */ ++} + + /* Call DH_compute_key() and ensure that we left-pad short results instead of + * leaving junk bytes at the end of the buffer. */ diff --git a/SOURCES/Use-imported-soft-pkcs11-for-tests.patch b/SOURCES/Use-imported-soft-pkcs11-for-tests.patch new file mode 100644 index 0000000..0be2d97 --- /dev/null +++ b/SOURCES/Use-imported-soft-pkcs11-for-tests.patch @@ -0,0 +1,472 @@ +From 43f5837eecd5022c525efcfb3605af16958dc59a Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 20 Jun 2019 13:41:57 -0400 +Subject: [PATCH] Use imported soft-pkcs11 for tests + +Update the soft-pkcs11 code for OpenSSL 1.1, fix some warnings, +integrate it into the build system, and use it for the PKINIT tests. + +(cherry picked from commit e5ef7b69765353ea62ad8712a229ed4e90a8fe17) +(cherry picked from commit 47e66724b9d5cfef84965d99c83d29e4739932e3) +--- + src/configure.in | 1 + + src/tests/Makefile.in | 2 +- + src/tests/softpkcs11/Makefile.in | 21 ++++ + src/tests/softpkcs11/deps | 6 ++ + src/tests/softpkcs11/main.c | 124 +++++++++++++++++------- + src/tests/softpkcs11/softpkcs11.exports | 39 ++++++++ + src/tests/t_pkinit.py | 18 +--- + 7 files changed, 162 insertions(+), 49 deletions(-) + create mode 100644 src/tests/softpkcs11/Makefile.in + create mode 100644 src/tests/softpkcs11/deps + create mode 100644 src/tests/softpkcs11/softpkcs11.exports + +diff --git a/src/configure.in b/src/configure.in +index 93aec682e..9f6b67b44 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -1086,6 +1086,7 @@ int i = 1; + fi + if test "$k5_cv_openssl_version_okay" = yes && (test "$enable_pkinit" = yes || test "$enable_pkinit" = try); then + K5_GEN_MAKEFILE(plugins/preauth/pkinit) ++ K5_GEN_MAKEFILE(tests/softpkcs11) + PKINIT=yes + AC_CHECK_LIB(crypto, CMS_get0_content, [AC_DEFINE([HAVE_OPENSSL_CMS], 1, [Define if OpenSSL supports cms.])]) + elif test "$k5_cv_openssl_version_okay" = no && test "$enable_pkinit" = yes; then +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index e27617ee2..ab958eb4c 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -1,7 +1,7 @@ + mydir=tests + BUILDTOP=$(REL).. + SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \ +- gss-threads misc threads ++ gss-threads misc threads softpkcs11 + + RUN_DB_TEST = $(RUN_SETUP) KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf \ + LC_ALL=C $(VALGRIND) +diff --git a/src/tests/softpkcs11/Makefile.in b/src/tests/softpkcs11/Makefile.in +new file mode 100644 +index 000000000..e89678154 +--- /dev/null ++++ b/src/tests/softpkcs11/Makefile.in +@@ -0,0 +1,21 @@ ++mydir=tests$(S)softpkcs11 ++BUILDTOP=$(REL)..$(S).. ++ ++LOCALINCLUDES = -I$(top_srcdir)/plugins/preauth/pkinit ++ ++LIBBASE=softpkcs11 ++LIBMAJOR=0 ++LIBMINOR=0 ++ ++SHLIB_EXPLIBS=$(SUPPORT_LIB) -lcrypto ++SHLIB_EXPDEPS=$(SUPPORT_DEPLIB) ++ ++STLIBOBJS=main.o ++ ++SRCS=$(srcdir)/main.c ++ ++all-unix: all-libs ++clean-unix:: clean-libs clean-libobjs ++ ++@libnover_frag@ ++@libobj_frag@ +diff --git a/src/tests/softpkcs11/deps b/src/tests/softpkcs11/deps +new file mode 100644 +index 000000000..1e82d9572 +--- /dev/null ++++ b/src/tests/softpkcs11/deps +@@ -0,0 +1,6 @@ ++# ++# Generated makefile dependencies follow. ++# ++main.so main.po $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \ ++ $(top_srcdir)/plugins/preauth/pkinit/pkcs11.h main.c +diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c +index 2acec5169..5255323d3 100644 +--- a/src/tests/softpkcs11/main.c ++++ b/src/tests/softpkcs11/main.c +@@ -1,3 +1,4 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ + /* + * Copyright (c) 2004-2006, Stockholms universitet + * (Stockholm University, Stockholm Sweden) +@@ -31,7 +32,57 @@ + * POSSIBILITY OF SUCH DAMAGE. + */ + +-#include "locl.h" ++#include "k5-platform.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa) ++#define RSA_PKCS1_OpenSSL RSA_PKCS1_SSLeay ++#define RSA_get0_key compat_rsa_get0_key ++static void ++compat_rsa_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, ++ const BIGNUM **d) ++{ ++ if (n != NULL) ++ *n = rsa->n; ++ if (e != NULL) ++ *e = rsa->e; ++ if (d != NULL) ++ *d = rsa->d; ++} ++#endif ++ ++#define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \ ++ { \ ++ unsigned char *p; \ ++ (BL) = i2d_##T((S), NULL); \ ++ if ((BL) <= 0) { \ ++ (R) = EINVAL; \ ++ } else { \ ++ (B) = malloc((BL)); \ ++ if ((B) == NULL) { \ ++ (R) = ENOMEM; \ ++ } else { \ ++ p = (B); \ ++ (R) = 0; \ ++ (BL) = i2d_##T((S), &p); \ ++ if ((BL) <= 0) { \ ++ free((B)); \ ++ (R) = EINVAL; \ ++ } \ ++ } \ ++ } \ ++ } + + /* RCSID("$Id: main.c,v 1.24 2006/01/11 12:42:53 lha Exp $"); */ + +@@ -124,7 +175,7 @@ st_logf(const char *fmt, ...) + } + + static void +-snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...) ++snprintf_fill(char *str, int size, char fillchar, const char *fmt, ...) + { + int len; + va_list ap; +@@ -141,19 +192,19 @@ snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...) + #endif + + #define VERIFY_SESSION_HANDLE(s, state) \ +-{ \ +- CK_RV ret; \ +- ret = verify_session_handle(s, state); \ +- if (ret != CKR_OK) { \ +- /* return CKR_OK */; \ +- } \ +-} ++ { \ ++ CK_RV vshret; \ ++ vshret = verify_session_handle(s, state); \ ++ if (vshret != CKR_OK) { \ ++ /* return CKR_OK */; \ ++ } \ ++ } + + static CK_RV + verify_session_handle(CK_SESSION_HANDLE hSession, + struct session_state **state) + { +- int i; ++ size_t i; + + for (i = 0; i < MAX_NUM_SESSION; i++){ + if (soft_token.state[i].session_handle == hSession) +@@ -361,16 +412,20 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key) + CK_ULONG modulus_bits = 0; + CK_BYTE *exponent = NULL; + size_t exponent_len = 0; ++ RSA *rsa; ++ const BIGNUM *n, *e; + +- modulus_bits = BN_num_bits(key->pkey.rsa->n); ++ rsa = EVP_PKEY_get0_RSA(key); ++ RSA_get0_key(rsa, &n, &e, NULL); ++ modulus_bits = BN_num_bits(n); + +- modulus_len = BN_num_bytes(key->pkey.rsa->n); ++ modulus_len = BN_num_bytes(n); + modulus = malloc(modulus_len); +- BN_bn2bin(key->pkey.rsa->n, modulus); ++ BN_bn2bin(n, modulus); + +- exponent_len = BN_num_bytes(key->pkey.rsa->e); ++ exponent_len = BN_num_bytes(e); + exponent = malloc(exponent_len); +- BN_bn2bin(key->pkey.rsa->e, exponent); ++ BN_bn2bin(e, exponent); + + add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len); + add_object_attribute(o, 0, CKA_MODULUS_BITS, +@@ -378,7 +433,7 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key) + add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT, + exponent, exponent_len); + +- RSA_set_method(key->pkey.rsa, RSA_PKCS1_SSLeay()); ++ RSA_set_method(rsa, RSA_PKCS1_OpenSSL()); + + free(modulus); + free(exponent); +@@ -474,7 +529,7 @@ add_certificate(char *label, + o->u.cert = cert; + public_key = X509_get_pubkey(o->u.cert); + +- switch (EVP_PKEY_type(public_key->type)) { ++ switch (EVP_PKEY_base_id(public_key)) { + case EVP_PKEY_RSA: + key_type = CKK_RSA; + break; +@@ -604,8 +659,8 @@ add_certificate(char *label, + /* XXX verify keytype */ + + if (key_type == CKK_RSA) +- RSA_set_method(o->u.private_key.key->pkey.rsa, +- RSA_PKCS1_SSLeay()); ++ RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key), ++ RSA_PKCS1_OpenSSL()); + + if (X509_check_private_key(cert, o->u.private_key.key) != 1) { + EVP_PKEY_free(o->u.private_key.key); +@@ -755,8 +810,9 @@ CK_RV + C_Initialize(CK_VOID_PTR a) + { + CK_C_INITIALIZE_ARGS_PTR args = a; ++ size_t i; ++ + st_logf("Initialize\n"); +- int i; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); +@@ -825,7 +881,7 @@ C_Initialize(CK_VOID_PTR a) + CK_RV + C_Finalize(CK_VOID_PTR args) + { +- int i; ++ size_t i; + + st_logf("Finalize\n"); + +@@ -1008,7 +1064,7 @@ C_OpenSession(CK_SLOT_ID slotID, + CK_NOTIFY Notify, + CK_SESSION_HANDLE_PTR phSession) + { +- int i; ++ size_t i; + + st_logf("OpenSession: slot: %d\n", (int)slotID); + +@@ -1050,7 +1106,7 @@ C_CloseSession(CK_SESSION_HANDLE hSession) + CK_RV + C_CloseAllSessions(CK_SLOT_ID slotID) + { +- int i; ++ size_t i; + + st_logf("CloseAllSessions\n"); + +@@ -1127,7 +1183,8 @@ C_Login(CK_SESSION_HANDLE hSession, + } + + /* XXX check keytype */ +- RSA_set_method(o->u.private_key.key->pkey.rsa, RSA_PKCS1_SSLeay()); ++ RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key), ++ RSA_PKCS1_OpenSSL()); + + if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) { + EVP_PKEY_free(o->u.private_key.key); +@@ -1226,7 +1283,6 @@ C_FindObjectsInit(CK_SESSION_HANDLE hSession, + } + if (ulCount) { + CK_ULONG i; +- size_t len; + + print_attributes(pTemplate, ulCount); + +@@ -1415,7 +1471,7 @@ C_Encrypt(CK_SESSION_HANDLE hSession, + return CKR_ARGUMENTS_BAD; + } + +- rsa = o->u.public_key->pkey.rsa; ++ rsa = EVP_PKEY_get0_RSA(o->u.public_key); + + if (rsa == NULL) + return CKR_ARGUMENTS_BAD; +@@ -1445,7 +1501,7 @@ C_Encrypt(CK_SESSION_HANDLE hSession, + goto out; + } + +- if (buffer_len + padding_len < ulDataLen) { ++ if ((CK_ULONG)buffer_len + padding_len < ulDataLen) { + ret = CKR_ARGUMENTS_BAD; + goto out; + } +@@ -1566,7 +1622,7 @@ C_Decrypt(CK_SESSION_HANDLE hSession, + return CKR_ARGUMENTS_BAD; + } + +- rsa = o->u.private_key.key->pkey.rsa; ++ rsa = EVP_PKEY_get0_RSA(o->u.private_key.key); + + if (rsa == NULL) + return CKR_ARGUMENTS_BAD; +@@ -1596,7 +1652,7 @@ C_Decrypt(CK_SESSION_HANDLE hSession, + goto out; + } + +- if (buffer_len + padding_len < ulEncryptedDataLen) { ++ if ((CK_ULONG)buffer_len + padding_len < ulEncryptedDataLen) { + ret = CKR_ARGUMENTS_BAD; + goto out; + } +@@ -1725,7 +1781,7 @@ C_Sign(CK_SESSION_HANDLE hSession, + return CKR_ARGUMENTS_BAD; + } + +- rsa = o->u.private_key.key->pkey.rsa; ++ rsa = EVP_PKEY_get0_RSA(o->u.private_key.key); + + if (rsa == NULL) + return CKR_ARGUMENTS_BAD; +@@ -1754,7 +1810,7 @@ C_Sign(CK_SESSION_HANDLE hSession, + goto out; + } + +- if (buffer_len < ulDataLen + padding_len) { ++ if ((CK_ULONG)buffer_len < ulDataLen + padding_len) { + ret = CKR_ARGUMENTS_BAD; + goto out; + } +@@ -1872,7 +1928,7 @@ C_Verify(CK_SESSION_HANDLE hSession, + return CKR_ARGUMENTS_BAD; + } + +- rsa = o->u.public_key->pkey.rsa; ++ rsa = EVP_PKEY_get0_RSA(o->u.public_key); + + if (rsa == NULL) + return CKR_ARGUMENTS_BAD; +@@ -1900,7 +1956,7 @@ C_Verify(CK_SESSION_HANDLE hSession, + goto out; + } + +- if (buffer_len < ulDataLen) { ++ if ((CK_ULONG)buffer_len < ulDataLen) { + ret = CKR_ARGUMENTS_BAD; + goto out; + } +@@ -1926,7 +1982,7 @@ C_Verify(CK_SESSION_HANDLE hSession, + if (len > buffer_len) + abort(); + +- if (len != ulSignatureLen) { ++ if ((CK_ULONG)len != ulSignatureLen) { + ret = CKR_GENERAL_ERROR; + goto out; + } +diff --git a/src/tests/softpkcs11/softpkcs11.exports b/src/tests/softpkcs11/softpkcs11.exports +new file mode 100644 +index 000000000..aa7284511 +--- /dev/null ++++ b/src/tests/softpkcs11/softpkcs11.exports +@@ -0,0 +1,39 @@ ++C_CloseAllSessions ++C_CloseSession ++C_Decrypt ++C_DecryptFinal ++C_DecryptInit ++C_DecryptUpdate ++C_DigestInit ++C_Encrypt ++C_EncryptFinal ++C_EncryptInit ++C_EncryptUpdate ++C_Finalize ++C_FindObjects ++C_FindObjectsFinal ++C_FindObjectsInit ++C_GenerateRandom ++C_GetAttributeValue ++C_GetFunctionList ++C_GetInfo ++C_GetMechanismInfo ++C_GetMechanismList ++C_GetObjectSize ++C_GetSessionInfo ++C_GetSlotInfo ++C_GetSlotList ++C_GetTokenInfo ++C_Initialize ++C_InitToken ++C_Login ++C_Logout ++C_OpenSession ++C_Sign ++C_SignFinal ++C_SignInit ++C_SignUpdate ++C_Verify ++C_VerifyFinal ++C_VerifyInit ++C_VerifyUpdate +diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py +index 1dadb1b96..384bf1426 100755 +--- a/src/tests/t_pkinit.py ++++ b/src/tests/t_pkinit.py +@@ -4,14 +4,7 @@ from k5test import * + if not os.path.exists(os.path.join(plugins, 'preauth', 'pkinit.so')): + skip_rest('PKINIT tests', 'PKINIT module not built') + +-# Check if soft-pkcs11.so is available. +-try: +- import ctypes +- lib = ctypes.LibraryLoader(ctypes.CDLL).LoadLibrary('soft-pkcs11.so') +- del lib +- have_soft_pkcs11 = True +-except: +- have_soft_pkcs11 = False ++soft_pkcs11 = os.path.join(buildtop, 'tests', 'softpkcs11', 'softpkcs11.so') + + # Construct a krb5.conf fragment configuring pkinit. + certs = os.path.join(srctop, 'tests', 'dejagnu', 'pkinit-certs') +@@ -69,9 +62,9 @@ p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12 + p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12 + p12_generic_identity = 'PKCS12:%s' % generic_p12 + p12_enc_identity = 'PKCS12:%s' % user_enc_p12 +-p11_identity = 'PKCS11:soft-pkcs11.so' +-p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:' +- 'slotid=1:token=SoftToken (token)') ++p11_identity = 'PKCS11:' + soft_pkcs11 ++p11_token_identity = ('PKCS11:module_name=' + soft_pkcs11 + ++ ':slotid=1:token=SoftToken (token)') + + # Start a realm with the test kdb module for the following UPN SAN tests. + realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=alias_kdc_conf, +@@ -398,9 +391,6 @@ realm.klist(realm.user_princ) + realm.kinit(realm.user_princ, flags=['-X', 'X509_user_identity=,'], + expected_code=1, expected_msg='Preauthentication failed while') + +-if not have_soft_pkcs11: +- skip_rest('PKINIT PKCS11 tests', 'soft-pkcs11.so not found') +- + softpkcs11rc = os.path.join(os.getcwd(), 'testdir', 'soft-pkcs11.rc') + realm.env['SOFTPKCS11RC'] = softpkcs11rc + diff --git a/SOURCES/Use-openssl-s-PRNG-in-FIPS-mode.patch b/SOURCES/Use-openssl-s-PRNG-in-FIPS-mode.patch deleted file mode 100644 index 632859f..0000000 --- a/SOURCES/Use-openssl-s-PRNG-in-FIPS-mode.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 196ee40d489e4e6a72232a3cdbb7af19a72362b3 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 4 Jan 2019 17:00:15 -0500 -Subject: [PATCH] Use openssl's PRNG in FIPS mode - -(cherry picked from commit 31277d79675a76612015ea00d420b41b9a232d5a) ---- - src/lib/crypto/krb/prng.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c -index cb9ca9b98..f0e9984ca 100644 ---- a/src/lib/crypto/krb/prng.c -+++ b/src/lib/crypto/krb/prng.c -@@ -26,6 +26,8 @@ - - #include "crypto_int.h" - -+#include -+ - krb5_error_code KRB5_CALLCONV - krb5_c_random_seed(krb5_context context, krb5_data *data) - { -@@ -99,9 +101,16 @@ krb5_boolean - k5_get_os_entropy(unsigned char *buf, size_t len, int strong) - { - const char *device; --#if defined(__linux__) && defined(SYS_getrandom) - int r; - -+ /* A wild FIPS mode appeared! */ -+ if (FIPS_mode()) { -+ /* The return codes on this API are not good */ -+ r = RAND_bytes(buf, len); -+ return r == 1; -+ } -+ -+#if defined(__linux__) && defined(SYS_getrandom) - while (len > 0) { - /* - * Pull from the /dev/urandom pool, but require it to have been seeded. diff --git a/SOURCES/krb5-1.17post2-DES-3DES-fixups.patch b/SOURCES/krb5-1.17post2-DES-3DES-fixups.patch new file mode 100644 index 0000000..0fcb76c --- /dev/null +++ b/SOURCES/krb5-1.17post2-DES-3DES-fixups.patch @@ -0,0 +1,103 @@ +From fe66536c1b7aec67233739df97cbe0301ee6475e Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 19 Nov 2019 15:03:19 -0500 +Subject: [PATCH] krb5-1.17post2 DES/3DES fixups + +Kept separate from the other patch because rawhide doesn't have DES. + +post2 adds krb5kdf workarounds. +--- + src/lib/crypto/krb/derive.c | 6 +++++- + src/lib/crypto/openssl/enc_provider/des.c | 9 +++++++++ + src/lib/crypto/openssl/enc_provider/des3.c | 6 ++++++ + 3 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c +index 915a173dd..ebdab69bc 100644 +--- a/src/lib/crypto/krb/derive.c ++++ b/src/lib/crypto/krb/derive.c +@@ -348,6 +348,7 @@ cleanup: + zapfree(prf.data, blocksize); + return ret; + } ++#endif /* OSSL_KDFS */ + + static krb5_error_code + builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc, +@@ -400,7 +401,6 @@ cleanup: + zapfree(block.data, blocksize); + return ret; + } +-#endif /* OSSL_KDFS */ + + krb5_error_code + k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash, +@@ -432,6 +432,10 @@ k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, + krb5_key inkey, krb5_data *outrnd, + const krb5_data *in_constant) + { ++ /* DES (single and triple). They'll be gone very soon. */ ++ if (enc->keylength == 8 || enc->keylength == 24) ++ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant); ++ + #ifdef OSSL_KDFS + return openssl_krb5kdf(enc, inkey, outrnd, in_constant); + #else +diff --git a/src/lib/crypto/openssl/enc_provider/des.c b/src/lib/crypto/openssl/enc_provider/des.c +index a662db512..7d17d287e 100644 +--- a/src/lib/crypto/openssl/enc_provider/des.c ++++ b/src/lib/crypto/openssl/enc_provider/des.c +@@ -85,6 +85,9 @@ k5_des_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx; + krb5_boolean empty; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + ret = validate(key, ivec, data, num_data, &empty); + if (ret != 0 || empty) + return ret; +@@ -133,6 +136,9 @@ k5_des_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx; + krb5_boolean empty; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + ret = validate(key, ivec, data, num_data, &empty); + if (ret != 0 || empty) + return ret; +@@ -182,6 +188,9 @@ k5_des_cbc_mac(krb5_key key, const krb5_crypto_iov *data, size_t num_data, + DES_key_schedule sched; + krb5_boolean empty; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + ret = validate(key, ivec, data, num_data, &empty); + if (ret != 0) + return ret; +diff --git a/src/lib/crypto/openssl/enc_provider/des3.c b/src/lib/crypto/openssl/enc_provider/des3.c +index 1c439c2cd..8be555a8d 100644 +--- a/src/lib/crypto/openssl/enc_provider/des3.c ++++ b/src/lib/crypto/openssl/enc_provider/des3.c +@@ -84,6 +84,9 @@ k5_des3_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx; + krb5_boolean empty; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + ret = validate(key, ivec, data, num_data, &empty); + if (ret != 0 || empty) + return ret; +@@ -133,6 +136,9 @@ k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx; + krb5_boolean empty; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + ret = validate(key, ivec, data, num_data, &empty); + if (ret != 0 || empty) + return ret; diff --git a/SOURCES/krb5-1.17post6-FIPS-with-PRNG-and-RADIUS-and-MD4.patch b/SOURCES/krb5-1.17post6-FIPS-with-PRNG-and-RADIUS-and-MD4.patch new file mode 100644 index 0000000..308137f --- /dev/null +++ b/SOURCES/krb5-1.17post6-FIPS-with-PRNG-and-RADIUS-and-MD4.patch @@ -0,0 +1,568 @@ +From 2a4e2418875b41c3273db5f6b4e9e1b01c1fb5ff Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 9 Nov 2018 15:12:21 -0500 +Subject: [PATCH] krb5-1.17post6 FIPS with PRNG and RADIUS and MD4 + +NB: Use openssl's PRNG in FIPS mode and taint within krad. + +A lot of the FIPS error conditions from OpenSSL are incredibly +mysterious (at best, things return NULL unexpectedly; at worst, +internal assertions are tripped; most of the time, you just get +ENOMEM). In order to cope with this, we need to have some level of +awareness of what we can and can't safely call. + +This will slow down some calls slightly (FIPS_mode() takes multiple +locks), but not for any ciphers we care about - which is to say that +AES is fine. Shame about SPAKE though. + +post6 restores MD4 (and therefore keygen-only RC4). + +(cherry picked from commit 80b56b04d90fcacd9f78fed305c7d5528d863b38) +--- + src/lib/crypto/krb/prng.c | 11 ++++- + .../crypto/openssl/enc_provider/camellia.c | 6 +++ + src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++++- + .../crypto/openssl/hash_provider/hash_evp.c | 12 +++++ + src/lib/crypto/openssl/hmac.c | 6 ++- + src/lib/krad/attr.c | 45 ++++++++++++++----- + src/lib/krad/attrset.c | 5 ++- + src/lib/krad/internal.h | 13 +++++- + src/lib/krad/packet.c | 22 ++++----- + src/lib/krad/remote.c | 10 ++++- + src/lib/krad/t_attr.c | 3 +- + src/lib/krad/t_attrset.c | 4 +- + src/plugins/preauth/spake/spake_client.c | 6 +++ + src/plugins/preauth/spake/spake_kdc.c | 6 +++ + 14 files changed, 129 insertions(+), 33 deletions(-) + +diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c +index cb9ca9b98..f0e9984ca 100644 +--- a/src/lib/crypto/krb/prng.c ++++ b/src/lib/crypto/krb/prng.c +@@ -26,6 +26,8 @@ + + #include "crypto_int.h" + ++#include ++ + krb5_error_code KRB5_CALLCONV + krb5_c_random_seed(krb5_context context, krb5_data *data) + { +@@ -99,9 +101,16 @@ krb5_boolean + k5_get_os_entropy(unsigned char *buf, size_t len, int strong) + { + const char *device; +-#if defined(__linux__) && defined(SYS_getrandom) + int r; + ++ /* A wild FIPS mode appeared! */ ++ if (FIPS_mode()) { ++ /* The return codes on this API are not good */ ++ r = RAND_bytes(buf, len); ++ return r == 1; ++ } ++ ++#if defined(__linux__) && defined(SYS_getrandom) + while (len > 0) { + /* + * Pull from the /dev/urandom pool, but require it to have been seeded. +diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c +index 2da691329..f79679a0b 100644 +--- a/src/lib/crypto/openssl/enc_provider/camellia.c ++++ b/src/lib/crypto/openssl/enc_provider/camellia.c +@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data, + unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE]; + struct iov_cursor cursor; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + if (output->length < CAMELLIA_BLOCK_SIZE) + return KRB5_BAD_MSIZE; + +@@ -331,6 +334,9 @@ static krb5_error_code + krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage, + krb5_data *state) + { ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + state->length = 16; + state->data = (void *) malloc(16); + if (state->data == NULL) +diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c +index a65d57b7a..6ccaca94a 100644 +--- a/src/lib/crypto/openssl/enc_provider/rc4.c ++++ b/src/lib/crypto/openssl/enc_provider/rc4.c +@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data, + EVP_CIPHER_CTX *ctx = NULL; + struct arcfour_state *arcstate; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + arcstate = (state != NULL) ? (void *)state->data : NULL; + if (arcstate != NULL) { + ctx = arcstate->ctx; +@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data, + static void + k5_arcfour_free_state(krb5_data *state) + { +- struct arcfour_state *arcstate = (void *)state->data; ++ struct arcfour_state *arcstate; ++ ++ if (FIPS_mode()) ++ return; ++ ++ arcstate = (void *) state->data; + + EVP_CIPHER_CTX_free(arcstate->ctx); + free(arcstate); +@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key, + { + struct arcfour_state *arcstate; + ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + /* + * The cipher state here is a saved pointer to a struct arcfour_state + * object, rather than a flat byte array as in most enc providers. The +diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c +index 957ed8d9c..915da9dbe 100644 +--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c ++++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c +@@ -49,6 +49,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data, + if (ctx == NULL) + return ENOMEM; + ++ if (type == EVP_md4()) { ++ /* See comment below in hash_md4(). */ ++ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); ++ } ++ + ok = EVP_DigestInit_ex(ctx, type, NULL); + for (i = 0; i < num_data; i++) { + if (!SIGN_IOV(&data[i])) +@@ -64,12 +69,19 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data, + static krb5_error_code + hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) + { ++ /* ++ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used ++ * by IPA. These keys are only used along a (separately) secured channel ++ * for legacy reasons when performing trusts to Active Directory. ++ */ + return hash_evp(EVP_md4(), data, num_data, output); + } + + static krb5_error_code + hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) + { ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; + return hash_evp(EVP_md5(), data, num_data, output); + } + +diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c +index b2db6ec02..d94d9ac94 100644 +--- a/src/lib/crypto/openssl/hmac.c ++++ b/src/lib/crypto/openssl/hmac.c +@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash) + return EVP_sha256(); + else if (!strncmp(hash->hash_name, "SHA-384",7)) + return EVP_sha384(); +- else if (!strncmp(hash->hash_name, "MD5", 3)) ++ ++ if (FIPS_mode()) ++ return NULL; ++ ++ if (!strncmp(hash->hash_name, "MD5", 3)) + return EVP_md5(); + else if (!strncmp(hash->hash_name, "MD4", 3)) + return EVP_md4(); +diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c +index 9c13d9d75..275327e67 100644 +--- a/src/lib/krad/attr.c ++++ b/src/lib/krad/attr.c +@@ -30,6 +30,7 @@ + #include + #include "internal.h" + ++#include + #include + + /* RFC 2865 */ +@@ -38,7 +39,8 @@ + typedef krb5_error_code + (*attribute_transform_fn)(krb5_context ctx, const char *secret, + const unsigned char *auth, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *is_fips); + + typedef struct { + const char *name; +@@ -51,12 +53,14 @@ typedef struct { + static krb5_error_code + user_password_encode(krb5_context ctx, const char *secret, + const unsigned char *auth, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *is_fips); + + static krb5_error_code + user_password_decode(krb5_context ctx, const char *secret, + const unsigned char *auth, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *ignored); + + static const attribute_record attributes[UCHAR_MAX] = { + {"User-Name", 1, MAX_ATTRSIZE, NULL, NULL}, +@@ -128,7 +132,8 @@ static const attribute_record attributes[UCHAR_MAX] = { + static krb5_error_code + user_password_encode(krb5_context ctx, const char *secret, + const unsigned char *auth, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *is_fips) + { + const unsigned char *indx; + krb5_error_code retval; +@@ -154,8 +159,14 @@ user_password_encode(krb5_context ctx, const char *secret, + for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) { + memcpy(tmp.data + seclen, indx, BLOCKSIZE); + +- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp, +- &sum); ++ if (FIPS_mode()) { ++ /* Skip encryption here. Taint so that we won't pass it out of ++ * the machine by accident. */ ++ *is_fips = TRUE; ++ sum.contents = calloc(1, BLOCKSIZE); ++ } else ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp, ++ &sum); + if (retval != 0) { + zap(tmp.data, tmp.length); + zap(outbuf, len); +@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret, + static krb5_error_code + user_password_decode(krb5_context ctx, const char *secret, + const unsigned char *auth, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *is_fips) + { + const unsigned char *indx; + krb5_error_code retval; +@@ -204,8 +216,14 @@ user_password_decode(krb5_context ctx, const char *secret, + for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) { + memcpy(tmp.data + seclen, indx, BLOCKSIZE); + +- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, +- &tmp, &sum); ++ if (FIPS_mode()) { ++ /* Skip encryption here. Taint so that we won't pass it out of ++ * the machine by accident. */ ++ *is_fips = TRUE; ++ sum.contents = calloc(1, BLOCKSIZE); ++ } else ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, ++ &tmp, &sum); + if (retval != 0) { + zap(tmp.data, tmp.length); + zap(outbuf, in->length); +@@ -248,7 +266,7 @@ krb5_error_code + kr_attr_encode(krb5_context ctx, const char *secret, + const unsigned char *auth, krad_attr type, + const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE], +- size_t *outlen) ++ size_t *outlen, krb5_boolean *is_fips) + { + krb5_error_code retval; + +@@ -265,7 +283,8 @@ kr_attr_encode(krb5_context ctx, const char *secret, + return 0; + } + +- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen); ++ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen, ++ is_fips); + } + + krb5_error_code +@@ -274,6 +293,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, + unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) + { + krb5_error_code retval; ++ krb5_boolean ignored; + + retval = kr_attr_valid(type, in); + if (retval != 0) +@@ -288,7 +308,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, + return 0; + } + +- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen); ++ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen, ++ &ignored); + } + + krad_attr +diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c +index 03c613716..d89982a13 100644 +--- a/src/lib/krad/attrset.c ++++ b/src/lib/krad/attrset.c +@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy) + krb5_error_code + kr_attrset_encode(const krad_attrset *set, const char *secret, + const unsigned char *auth, +- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen) ++ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, ++ krb5_boolean *is_fips) + { + unsigned char buffer[MAX_ATTRSIZE]; + krb5_error_code retval; +@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret, + + K5_TAILQ_FOREACH(a, &set->list, list) { + retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr, +- buffer, &attrlen); ++ buffer, &attrlen, is_fips); + if (retval != 0) + return retval; + +diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h +index 996a89372..a53ce31ce 100644 +--- a/src/lib/krad/internal.h ++++ b/src/lib/krad/internal.h +@@ -49,6 +49,13 @@ + + typedef struct krad_remote_st krad_remote; + ++struct krad_packet_st { ++ char buffer[KRAD_PACKET_SIZE_MAX]; ++ krad_attrset *attrset; ++ krb5_data pkt; ++ krb5_boolean is_fips; ++}; ++ + /* Validate constraints of an attribute. */ + krb5_error_code + kr_attr_valid(krad_attr type, const krb5_data *data); +@@ -57,7 +64,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data); + krb5_error_code + kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth, + krad_attr type, const krb5_data *in, +- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen, ++ krb5_boolean *is_fips); + + /* Decode an attribute. */ + krb5_error_code +@@ -69,7 +77,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, + krb5_error_code + kr_attrset_encode(const krad_attrset *set, const char *secret, + const unsigned char *auth, +- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen); ++ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, ++ krb5_boolean *is_fips); + + /* Decode attributes from a buffer. */ + krb5_error_code +diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c +index c597174b6..794ac84c4 100644 +--- a/src/lib/krad/packet.c ++++ b/src/lib/krad/packet.c +@@ -32,6 +32,7 @@ + #include + + #include ++#include + + typedef unsigned char uchar; + +@@ -53,12 +54,6 @@ typedef unsigned char uchar; + #define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH)) + #define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR)) + +-struct krad_packet_st { +- char buffer[KRAD_PACKET_SIZE_MAX]; +- krad_attrset *attrset; +- krb5_data pkt; +-}; +- + typedef struct { + uchar x[(UCHAR_MAX + 1) / 8]; + } idmap; +@@ -187,8 +182,13 @@ auth_generate_response(krb5_context ctx, const char *secret, + memcpy(data.data + response->pkt.length, secret, strlen(secret)); + + /* Hash it. */ +- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data, +- &hash); ++ if (FIPS_mode()) { ++ /* This checksum does very little security-wise anyway, so don't ++ * taint. */ ++ hash.contents = calloc(1, AUTH_FIELD_SIZE); ++ } else ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data, ++ &hash); + free(data.data); + if (retval != 0) + return retval; +@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, + + /* Encode the attributes. */ + retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt), +- &attrset_len); ++ &attrset_len, &pkt->is_fips); + if (retval != 0) + goto error; + +@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, + + /* Encode the attributes. */ + retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt), +- &attrset_len); ++ &attrset_len, &pkt->is_fips); + if (retval != 0) + goto error; + +@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret, + const krb5_data * + krad_packet_encode(const krad_packet *pkt) + { ++ if (pkt->is_fips) ++ return NULL; + return &pkt->pkt; + } + +diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c +index 437f7e91a..0f90443ce 100644 +--- a/src/lib/krad/remote.c ++++ b/src/lib/krad/remote.c +@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr) + request *r; + + K5_TAILQ_FOREACH(r, &rr->list, list) { +- tmp = krad_packet_encode(r->request); ++ tmp = &r->request->pkt; + + /* If the packet has already been sent, do nothing. */ + if (r->sent == tmp->length) +@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr) + if (req != NULL) { + K5_TAILQ_FOREACH(r, &rr->list, list) { + if (r->request == req && +- r->sent == krad_packet_encode(req)->length) { ++ r->sent == req->pkt.length) { + request_finish(r, 0, rsp); + break; + } +@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs, + (krad_packet_iter_cb)iterator, &r, &tmp); + if (retval != 0) + goto error; ++ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL && ++ rr->info->ai_family != AF_UNIX) { ++ /* This would expose cleartext passwords, so abort. */ ++ retval = ESOCKTNOSUPPORT; ++ goto error; ++ } + + K5_TAILQ_FOREACH(r, &rr->list, list) { + if (r->request == tmp) { +diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c +index eb2a780c8..4d285ad9d 100644 +--- a/src/lib/krad/t_attr.c ++++ b/src/lib/krad/t_attr.c +@@ -50,6 +50,7 @@ main() + const char *tmp; + krb5_data in; + size_t len; ++ krb5_boolean is_fips = FALSE; + + noerror(krb5_init_context(&ctx)); + +@@ -73,7 +74,7 @@ main() + in = string2data((char *)decoded); + retval = kr_attr_encode(ctx, secret, auth, + krad_attr_name2num("User-Password"), +- &in, outbuf, &len); ++ &in, outbuf, &len, &is_fips); + insist(retval == 0); + insist(len == sizeof(encoded)); + insist(memcmp(outbuf, encoded, len) == 0); +diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c +index 7928335ca..0f9576253 100644 +--- a/src/lib/krad/t_attrset.c ++++ b/src/lib/krad/t_attrset.c +@@ -49,6 +49,7 @@ main() + krb5_context ctx; + size_t len = 0, encode_len; + krb5_data tmp; ++ krb5_boolean is_fips = FALSE; + + noerror(krb5_init_context(&ctx)); + noerror(krad_attrset_new(ctx, &set)); +@@ -62,7 +63,8 @@ main() + noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp)); + + /* Encode attrset. */ +- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len)); ++ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len, ++ &is_fips)); + krad_attrset_free(set); + + /* Manually encode User-Name. */ +diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c +index 00734a13b..a3ce22b70 100644 +--- a/src/plugins/preauth/spake/spake_client.c ++++ b/src/plugins/preauth/spake/spake_client.c +@@ -38,6 +38,8 @@ + #include "groups.h" + #include + ++#include ++ + typedef struct reqstate_st { + krb5_pa_spake *msg; /* set in prep_questions, used in process */ + krb5_keyblock *initial_key; +@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; ++ ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + vt = (krb5_clpreauth_vtable)vtable; + vt->name = "spake"; + vt->pa_type_list = pa_types; +diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c +index 59e88409e..1b3e569e9 100644 +--- a/src/plugins/preauth/spake/spake_kdc.c ++++ b/src/plugins/preauth/spake/spake_kdc.c +@@ -41,6 +41,8 @@ + + #include + ++#include ++ + /* + * The SPAKE kdcpreauth module uses a secure cookie containing the following + * concatenated fields (all integer fields are big-endian): +@@ -578,6 +580,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; ++ ++ if (FIPS_mode()) ++ return KRB5_CRYPTO_INTERNAL; ++ + vt = (krb5_kdcpreauth_vtable)vtable; + vt->name = "spake"; + vt->pa_type_list = pa_types; diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec index afd52e3..b285a4b 100644 --- a/SPECS/krb5.spec +++ b/SPECS/krb5.spec @@ -18,12 +18,12 @@ Summary: The Kerberos network authentication system Name: krb5 Version: 1.17 # for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces) -Release: 9%{?dist} +Release: 18%{?dist} # lookaside-cached sources; two downloads and a build artifact -Source0: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz +Source0: https://web.mit.edu/kerberos/dist/krb5/1.17/krb5-%{version}%{prerelease}.tar.gz # rharwood has trust path to signing key and verifies on check-in -Source1: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz.asc +Source1: https://web.mit.edu/kerberos/dist/krb5/1.17/krb5-%{version}%{prerelease}.tar.gz.asc # This source is generated during the build because it is documentation. # To override this behavior (e.g., new upstream version), do: # tar cfT krb5-1.15.2-pdfs.tar /dev/null @@ -57,20 +57,26 @@ Patch33: krb5-1.13-dirsrv-accountlock.patch Patch34: krb5-1.9-debuginfo.patch Patch35: krb5-1.11-run_user_0.patch Patch36: krb5-1.11-kpasswdtest.patch -Patch87: In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch Patch88: Add-tests-for-KCM-ccache-type.patch Patch89: Properly-size-ifdef-in-k5_cccol_lock.patch Patch90: Fix-memory-leak-in-none-replay-cache-type.patch Patch91: Address-some-optimized-out-memset-calls.patch -Patch92: Use-openssl-s-PRNG-in-FIPS-mode.patch -Patch93: Become-FIPS-aware-with-3DES.patch -Patch94: FIPS-aware-SPAKE-group-negotiation.patch Patch95: In-rd_req_dec-always-log-non-permitted-enctypes.patch Patch96: In-kpropd-debug-log-proper-ticket-enctype-names.patch Patch97: Make-etype-names-in-KDC-logs-human-readable.patch Patch98: Mark-deprecated-enctypes-when-used.patch Patch99: Add-function-and-enctype-flag-for-deprecations.patch Patch100: Fix-argument-order-on-strlcpy-in-enctype_name.patch +Patch101: Fix-KCM-client-time-offset-propagation.patch +Patch102: Add-soft-pkcs11-source-code.patch +Patch103: Use-imported-soft-pkcs11-for-tests.patch +Patch104: Fix-Coverity-defects-in-soft-pkcs11-test-code.patch +Patch105: Fix-memory-leaks-in-soft-pkcs11-code.patch +Patch106: Avoid-alignment-warnings-in-openssl-rc4.c.patch +Patch107: Use-backported-version-of-OpenSSL-3-KDF-interface.patch +Patch108: krb5-1.17post6-FIPS-with-PRNG-and-RADIUS-and-MD4.patch +Patch109: krb5-1.17post2-DES-3DES-fixups.patch +Patch110: Put-KDB-authdata-first.patch License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -83,12 +89,12 @@ BuildRequires: gzip, ncurses-devel BuildRequires: python3-sphinx, texlive-pdftex, latexmk BuildRequires: libverto-devel BuildRequires: openldap-devel -BuildRequires: openssl-devel >= 0.9.8 BuildRequires: python3 BuildRequires: keyutils, keyutils-libs-devel >= 1.5.8 BuildRequires: libselinux-devel BuildRequires: pam-devel BuildRequires: tcl-devel +BuildRequires: openssl-devel >= 1:1.1.1c-4 # For autosetup BuildRequires: git @@ -153,6 +159,7 @@ Summary: The non-admin shared libraries used by Kerberos 5 Group: System Environment/Libraries Requires: coreutils, gawk, grep, sed Requires: keyutils-libs >= 1.5.8 +Requires: openssl-libs >= 1:1.1.1c-4 Requires: /etc/crypto-policies/back-ends/krb5.config %description libs @@ -683,6 +690,42 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Wed Feb 19 2020 Robbie Harwood - 1.17-18 +- Put KDB authdata first +- Resolves: #1800575 + +* Thu Nov 21 2019 Robbie Harwood - 1.17-17 +- OpenSSL has an epoch, apparently +- Resolves: #1754690 + +* Wed Nov 20 2019 Robbie Harwood - 1.17-16 +- Put openssl runtime requirement in the right place this time +- Resolves: #1754690 + +* Wed Nov 20 2019 Robbie Harwood - 1.17-15 +- Restore accidentally dropped patch +- Resolves: #1754690 + +* Wed Nov 20 2019 Robbie Harwood - 1.17-14 +- Fix krb5kdf support and add proper openssl version requirements +- Resolves: #1754690 + +* Tue Nov 19 2019 Robbie Harwood - 1.17-13 +- Full FIPS compliance +- Resolves: #1754690 + +* Tue Oct 15 2019 Robbie Harwood - 1.17-12 +- Backport soft-pkcs11 testing code +- Resolves: #1734158 + +* Tue Oct 15 2019 Robbie Harwood - 1.17-11 +- Fix KCM client time offset propagation +- Resolves: #1738553 + +* Tue Oct 15 2019 Robbie Harwood - 1.17-10 +- Fix source URLs in spec file +- Resolves: #1755959 + * Tue Sep 17 2019 Robbie Harwood - 1.17-9 - Fix argument order on strlcpy() in enctype_name() - Resolves: #1754369