summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-01-11 15:09:23 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-01-12 15:42:23 +0100
commit332475e9cf8cf7afe117e93555dfe24df898bc4b (patch)
treedf45239e64d003cfa3992c2efbbec7071a868b17
parent0a92ec601c3d33d6b939e2cd2e22302584fe8eea (diff)
downloadgnutls-332475e9cf8cf7afe117e93555dfe24df898bc4b.tar.gz
x509: introduced GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
That allows to print and write KRB5PrincipalName othernames in subject alternative name.
-rw-r--r--lib/gnutls.asn11
-rw-r--r--lib/gnutls_asn1_tab.c13
-rw-r--r--lib/includes/gnutls/gnutls.h.in7
-rw-r--r--lib/x509/Makefile.am3
-rw-r--r--lib/x509/common.h1
-rw-r--r--lib/x509/krb5.c324
-rw-r--r--lib/x509/krb5.h22
-rw-r--r--lib/x509/output.c6
-rw-r--r--lib/x509/virt-san.c23
9 files changed, 405 insertions, 5 deletions
diff --git a/lib/gnutls.asn b/lib/gnutls.asn
index 6342995330..76bad6fbb6 100644
--- a/lib/gnutls.asn
+++ b/lib/gnutls.asn
@@ -111,4 +111,15 @@ ECPrivateKey ::= SEQUENCE {
publicKey [1] BIT STRING OPTIONAL
}
+-- Structures used for the PKINIT othername variables
+PrincipalName ::= SEQUENCE {
+ name-type [0] INTEGER,
+ name-string [1] SEQUENCE OF GeneralString
+}
+
+KRB5PrincipalName ::= SEQUENCE {
+ realm [0] GeneralString,
+ principalName [1] PrincipalName
+}
+
END
diff --git a/lib/gnutls_asn1_tab.c b/lib/gnutls_asn1_tab.c
index 5da8f7d742..bc0e85ef5d 100644
--- a/lib/gnutls_asn1_tab.c
+++ b/lib/gnutls_asn1_tab.c
@@ -68,12 +68,23 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "ECPoint", 1073741831, NULL },
{ "ECParameters", 1610612754, NULL },
{ "namedCurve", 12, NULL },
- { "ECPrivateKey", 536870917, NULL },
+ { "ECPrivateKey", 1610612741, NULL },
{ "Version", 1073741827, NULL },
{ "privateKey", 1073741831, NULL },
{ "parameters", 1610637314, "ECParameters"},
{ NULL, 2056, "0"},
{ "publicKey", 536895494, NULL },
{ NULL, 2056, "1"},
+ { "PrincipalName", 1610612741, NULL },
+ { "name-type", 1610620931, NULL },
+ { NULL, 2056, "0"},
+ { "name-string", 536879115, NULL },
+ { NULL, 1073743880, "1"},
+ { NULL, 27, NULL },
+ { "KRB5PrincipalName", 536870917, NULL },
+ { "realm", 1610620955, NULL },
+ { NULL, 2056, "0"},
+ { "principalName", 536879106, "PrincipalName"},
+ { NULL, 2056, "1"},
{ NULL, 0, NULL }
};
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 759a0d6a4f..e9e613918d 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -2030,8 +2030,8 @@ gnutls_psk_set_server_params_function(gnutls_psk_server_credentials_t
* @GNUTLS_SAN_IPADDRESS: IP address SAN.
* @GNUTLS_SAN_OTHERNAME: OtherName SAN.
* @GNUTLS_SAN_DN: DN SAN.
- * @GNUTLS_SAN_OTHERNAME_XMPP: Virtual SAN, used by
- * gnutls_x509_crt_get_subject_alt_othername_oid.
+ * @GNUTLS_SAN_OTHERNAME_XMPP: Virtual SAN, used by certain functions for convenience.
+ * @GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL: Virtual SAN, used by certain functions for convenience.
*
* Enumeration of different subject alternative names types.
*/
@@ -2045,7 +2045,8 @@ typedef enum gnutls_x509_subject_alt_name_t {
/* The following are "virtual" subject alternative name types, in
that they are represented by an otherName value and an OID.
Used by gnutls_x509_crt_get_subject_alt_othername_oid. */
- GNUTLS_SAN_OTHERNAME_XMPP = 1000
+ GNUTLS_SAN_OTHERNAME_XMPP = 1000,
+ GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
} gnutls_x509_subject_alt_name_t;
struct gnutls_openpgp_crt_int;
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index c64f7cf9ba..34bb2384a9 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -65,7 +65,8 @@ libgnutls_x509_la_SOURCES = \
pkcs7-output.c \
virt-san.c \
virt-san.h \
- x509_ext_int.h
+ x509_ext_int.h \
+ krb5.c krb5.h
if ENABLE_OCSP
libgnutls_x509_la_SOURCES += ocsp.c ocsp_output.c
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 702c22bcae..445c3ddd10 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -70,6 +70,7 @@
#define ISO_SIG_RSA_SHA1_OID "1.3.14.3.2.29"
#define XMPP_OID "1.3.6.1.5.5.7.8.5"
+#define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
#define ASN1_NULL "\x05\x00"
#define ASN1_NULL_SIZE 2
diff --git a/lib/x509/krb5.c b/lib/x509/krb5.c
new file mode 100644
index 0000000000..45b71ba2b9
--- /dev/null
+++ b/lib/x509/krb5.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gnutls/gnutls.h>
+#include <libtasn1.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errors.h>
+#include "krb5.h"
+#include "common.h"
+
+#define _gnutls_asn2err(x) GNUTLS_E_ASN1_DER_ERROR
+
+#define MAX_COMPONENTS 6
+
+typedef struct krb5_principal_data {
+ char *realm;
+ char *data[MAX_COMPONENTS];
+ uint32_t length;
+ int8_t type;
+} krb5_principal_data;
+
+extern const asn1_static_node krb5_asn1_tab[];
+
+static void cleanup_principal(krb5_principal_data *princ)
+{
+ unsigned i;
+ if (princ) {
+ gnutls_free(princ->realm);
+ for (i=0;i<princ->length;i++)
+ gnutls_free(princ->data[i]);
+ memset(princ, 0, sizeof(*princ));
+ gnutls_free(princ);
+ }
+}
+
+static krb5_principal_data* name_to_principal(const char *_name)
+{
+ krb5_principal_data *princ;
+ char *p, *p2, *sp;
+ unsigned pos = 0;
+ char *name = NULL;
+
+ princ = gnutls_calloc(1, sizeof(struct krb5_principal_data));
+ if (princ == NULL)
+ return NULL;
+
+ name = gnutls_strdup(_name);
+ if (name == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ p = strrchr(name, '@');
+ p2 = strchr(name, '@');
+ if (p == NULL) {
+ /* unknown name type */
+ gnutls_assert();
+ goto fail;
+ }
+
+ princ->realm = gnutls_strdup(p+1);
+ if (princ->realm == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+ *p = 0;
+
+ if (p == p2) {
+ p = strtok_r(name, "/", &sp);
+ while(p) {
+ if (pos == MAX_COMPONENTS) {
+ _gnutls_debug_log("%s: Cannot parse names with more than %d components\n", __func__, MAX_COMPONENTS);
+ goto fail;
+ }
+
+ princ->data[pos] = gnutls_strdup(p);
+ if (princ->data[pos] == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ princ->length++;
+ pos++;
+
+ p = strtok_r(NULL, "/", &sp);
+ }
+
+ if ((princ->length == 2) && (strcmp (princ->data[0], "krbtgt") == 0)) {
+ princ->type = 2; /* KRB_NT_SRV_INST */
+ } else {
+ princ->type = 1; /* KRB_NT_PRINCIPAL */
+ }
+ } else { /* enterprise */
+ princ->data[0] = gnutls_strdup(name);
+ if (princ->data[0] == NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ princ->length++;
+ princ->type = 10; /* KRB_NT_ENTERPRISE */
+ }
+
+ goto cleanup;
+ fail:
+ cleanup_principal(princ);
+ princ = NULL;
+
+ cleanup:
+ gnutls_free(name);
+ return princ;
+}
+
+int _gnutls_krb5_principal_to_der(const char *name, gnutls_datum * der)
+{
+ int ret, result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ krb5_principal_data * princ;
+ unsigned i;
+
+ princ = name_to_principal(name);
+ if (princ == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.KRB5PrincipalName", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2, "realm", princ->realm, strlen(princ->realm));
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2, "principalName.name-type", &princ->type,
+ 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ for (i = 0; i < princ->length; i++) {
+ result =
+ asn1_write_value(c2, "principalName.name-string",
+ "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "principalName.name-string.?LAST",
+ princ->data[i], strlen(princ->data[i]));
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", der, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ cleanup_principal(princ);
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+static int principal_to_str(ASN1_TYPE c2, gnutls_buffer_st *str)
+{
+ gnutls_datum_t realm = {NULL, 0};
+ gnutls_datum_t component = {NULL, 0};
+ unsigned char name_type[2];
+ int ret, result, len;
+ unsigned i;
+ char val[128];
+
+ ret = _gnutls_x509_read_value(c2, "realm", &realm);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ len = sizeof(name_type);
+ result = asn1_read_value(c2, "principalName.name-type", name_type, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (len != 1 || (name_type[0] != 1 && name_type[0] != 2 && name_type[0] != 10)) {
+ ret = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ for (i=0;;i++) {
+ snprintf(val, sizeof(val), "principalName.name-string.?%u", i+1);
+ ret = _gnutls_x509_read_value(c2, val, &component);
+ if (ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ break;
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (i>0) {
+ ret = _gnutls_buffer_append_data(str, "/", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = _gnutls_buffer_append_data(str, component.data, component.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ _gnutls_free_datum(&component);
+ }
+
+ ret = _gnutls_buffer_append_data(str, "@", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(str, realm.data, realm.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ _gnutls_free_datum(&component);
+ gnutls_free(realm.data);
+ return ret;
+}
+
+int _gnutls_krb5_der_to_principal(const gnutls_datum * der, gnutls_datum_t *name)
+{
+ int ret, result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ gnutls_buffer_st str;
+
+ result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.KRB5PrincipalName", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_der_decoding(&c2, der->data, der->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ _gnutls_buffer_init(&str);
+
+ ret = principal_to_str(c2, &str);
+ if (ret < 0) {
+ /* for some reason we cannot convert to a human readable string
+ * the principal. Then we use the #HEX format.
+ */
+ _gnutls_buffer_reset(&str);
+ ret = _gnutls_buffer_append_data(&str, "#", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ _gnutls_buffer_hexprint(&str, der->data, der->size);
+ }
+
+ asn1_delete_structure(&c2);
+ return _gnutls_buffer_to_datum(&str, name, 1);
+
+ cleanup:
+ _gnutls_buffer_clear(&str);
+ asn1_delete_structure(&c2);
+ return ret;
+}
diff --git a/lib/x509/krb5.h b/lib/x509/krb5.h
new file mode 100644
index 0000000000..94d4867ec9
--- /dev/null
+++ b/lib/x509/krb5.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+int _gnutls_krb5_principal_to_der(const char *name, gnutls_datum * der);
+int _gnutls_krb5_der_to_principal(const gnutls_datum * der, gnutls_datum_t *name);
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 8c4c24e16f..6134e5b554 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -81,6 +81,7 @@ unsigned i;
#endif
if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
+ || type == GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
|| type == GNUTLS_SAN_RFC822NAME
|| type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
adds(str,
@@ -140,6 +141,11 @@ unsigned i;
case GNUTLS_SAN_OTHERNAME_XMPP:
addf(str, _("%sXMPP Address: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
+
+ case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
+ addf(str, _("%sKRB5Principal: %.*s\n"), prefix, name->size, NON_NULL(name->data));
+ break;
+
default:
addf(str, _("%sUnknown name: "), prefix);
_gnutls_buffer_hexprint(str, name->data, name->size);
diff --git a/lib/x509/virt-san.c b/lib/x509/virt-san.c
index cefcee68a0..83e5414479 100644
--- a/lib/x509/virt-san.c
+++ b/lib/x509/virt-san.c
@@ -26,6 +26,7 @@
#include "gnutls_int.h"
#include "x509_int.h"
#include "common.h"
+#include "krb5.h"
#include "virt-san.h"
static
@@ -35,6 +36,9 @@ int san_othername_to_virtual(const char *oid, size_t size)
if ((unsigned) size == (sizeof(XMPP_OID)-1)
&& memcmp(oid, XMPP_OID, sizeof(XMPP_OID)-1) == 0)
return GNUTLS_SAN_OTHERNAME_XMPP;
+ else if ((unsigned) size == (sizeof(KRB5_PRINCIPAL_OID)-1)
+ && memcmp(oid, KRB5_PRINCIPAL_OID, sizeof(KRB5_PRINCIPAL_OID)-1) == 0)
+ return GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL;
}
return GNUTLS_SAN_OTHERNAME;
@@ -46,6 +50,8 @@ const char * virtual_to_othername_oid(unsigned type)
switch(type) {
case GNUTLS_SAN_OTHERNAME_XMPP:
return XMPP_OID;
+ case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
+ return KRB5_PRINCIPAL_OID;
default:
return NULL;
}
@@ -89,6 +95,16 @@ int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutl
name->othername_oid.size = strlen(oid);
break;
+ case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
+ ret = _gnutls_krb5_principal_to_der((char*)san->data, &name->san);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ name->othername_oid.data = (void*)gnutls_strdup(oid);
+ name->othername_oid.size = strlen(oid);
+ name->type = GNUTLS_SAN_OTHERNAME;
+ break;
+
default:
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
}
@@ -138,6 +154,13 @@ int gnutls_x509_othername_to_virtual(const char *oid,
return ret;
}
return 0;
+ case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
+ ret = _gnutls_krb5_der_to_principal(othername, virt);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ return 0;
default:
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
}