@@ -16,6 +16,7 @@ obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
x509_key_parser-y := \
x509-asn1.o \
x509_akid-asn1.o \
+ x509_extusage-asn1.o \
x509_rsakey-asn1.o \
x509_cert_parser.o \
x509_public_key.o
@@ -23,13 +24,16 @@ x509_key_parser-y := \
$(obj)/x509_cert_parser.o: \
$(obj)/x509-asn1.h \
$(obj)/x509_akid-asn1.h \
+ $(obj)/x509_extusage-asn1.h \
$(obj)/x509_rsakey-asn1.h
$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
$(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h
+$(obj)/x509_extusage-asn1.o: $(obj)/x509_extusage-asn1.c $(obj)/x509_extusage-asn1.h
$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_akid-asn1.c x509_akid-asn1.h
+clean-files += x509_extusage-asn1.c x509_extusage-asn1.h
clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
#
@@ -246,7 +246,8 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
}
seq_puts(m, " [");
- /* put something here to indicate the key's capabilities */
+ if (subtype->describe_caps)
+ subtype->describe_caps(key, m);
seq_putc(m, ']');
}
}
@@ -42,6 +42,16 @@ const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
};
EXPORT_SYMBOL_GPL(pkey_id_type_name);
+static const char *const public_key_restrictions[NR__PKEY_USAGE_RESTRICTION] = {
+ [PKEY_USAGE_NOT_SPECIFIED] = "unrestricted",
+ [PKEY_RESTRICTED_USAGE] = "unspecified",
+ [PKEY_RESTRICTED_TO_OTHER] = "other use",
+ [PKEY_RESTRICTED_TO_MODULE_SIGNING] = "module sig",
+ [PKEY_RESTRICTED_TO_FIRMWARE_SIGNING] = "firmware sig",
+ [PKEY_RESTRICTED_TO_KEXEC_SIGNING] = "kexec sig",
+ [PKEY_RESTRICTED_TO_KEY_SIGNING] = "key sig",
+};
+
/*
* Provide a part of a description of the key for /proc/keys.
*/
@@ -56,6 +66,18 @@ static void public_key_describe(const struct key *asymmetric_key,
}
/*
+ * Describe capabilities/restrictions of the key for /proc/keys.
+ */
+static void public_key_describe_caps(const struct key *asymmetric_key,
+ struct seq_file *m)
+{
+ struct public_key *key = asymmetric_key->payload.data;
+
+ if (key)
+ seq_puts(m, public_key_restrictions[key->usage_restriction]);
+}
+
+/*
* Destroy a public key algorithm key.
*/
void public_key_destroy(void *payload)
@@ -123,6 +145,7 @@ struct asymmetric_key_subtype public_key_subtype = {
.name = "public_key",
.name_len = sizeof("public_key") - 1,
.describe = public_key_describe,
+ .describe_caps = public_key_describe_caps,
.destroy = public_key_destroy,
.verify_signature = public_key_verify_signature_2,
};
@@ -19,6 +19,7 @@
#include "x509_parser.h"
#include "x509-asn1.h"
#include "x509_akid-asn1.h"
+#include "x509_extusage-asn1.h"
#include "x509_rsakey-asn1.h"
struct x509_parse_context {
@@ -40,6 +41,8 @@ struct x509_parse_context {
const void *raw_akid; /* Raw authorityKeyId in ASN.1 */
const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */
unsigned akid_raw_issuer_size;
+ unsigned raw_extusage_size;
+ const void *raw_extusage; /* Raw extKeyUsage in ASN.1 */
};
/*
@@ -91,6 +94,20 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
if (ret < 0)
goto error_decode;
+ /* Decode the extended key usage information */
+ if (ctx->raw_extusage) {
+ pr_devel("EXTUSAGE: %u %*phN\n",
+ ctx->raw_extusage_size, ctx->raw_extusage_size,
+ ctx->raw_extusage);
+ ret = asn1_ber_decoder(&x509_extusage_decoder, ctx,
+ ctx->raw_extusage,
+ ctx->raw_extusage_size);
+ if (ret < 0) {
+ pr_warn("Couldn't decode extKeyUsage\n");
+ goto error_decode;
+ }
+ }
+
/* Decode the AuthorityKeyIdentifier */
if (ctx->raw_akid) {
pr_devel("AKID: %u %*phN\n",
@@ -471,6 +488,14 @@ int x509_process_extension(void *context, size_t hdrlen,
return 0;
}
+ if (ctx->last_oid == OID_extKeyUsage) {
+ /* Get hold of the extended key usage information */
+ ctx->raw_extusage = v;
+ ctx->raw_extusage_size = vlen;
+ ctx->cert->pub->usage_restriction = PKEY_RESTRICTED_USAGE;
+ return 0;
+ }
+
return 0;
}
@@ -605,3 +630,50 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
ctx->cert->akid_id = kid;
return 0;
}
+
+/*
+ * Note restriction to a purpose
+ */
+int x509_extusage_note_purpose(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ enum pkey_usage_restriction restriction;
+ char buffer[50];
+ enum OID oid;
+
+ sprint_oid(value, vlen, buffer, sizeof(buffer));
+ pr_debug("ExtUsage: %s\n", buffer);
+
+ oid = look_up_OID(value, vlen);
+ if (oid == OID__NR) {
+ pr_debug("Unknown extension: [%lu] %s\n",
+ (unsigned long)value - ctx->data, buffer);
+ return 0;
+ }
+
+ switch (oid) {
+ case OID_firmwareSigningOnlyKey:
+ restriction = PKEY_RESTRICTED_TO_FIRMWARE_SIGNING;
+ break;
+ case OID_moduleSigningOnlyKey:
+ restriction = PKEY_RESTRICTED_TO_MODULE_SIGNING;
+ break;
+ case OID_kexecSigningOnlyKey:
+ restriction = PKEY_RESTRICTED_TO_KEXEC_SIGNING;
+ break;
+ default:
+ restriction = PKEY_RESTRICTED_TO_OTHER;
+ break;
+ }
+
+ if (ctx->cert->pub->usage_restriction != PKEY_RESTRICTED_USAGE) {
+ pr_warn("Rejecting certificate with multiple restrictions\n");
+ return -EKEYREJECTED;
+ }
+
+ ctx->cert->pub->usage_restriction = restriction;
+ pr_debug("usage restriction %u\n", restriction);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,3 @@
+ExtKeyUsageSyntax ::= SEQUENCE OF KeyPurposeId
+
+KeyPurposeId ::= OBJECT IDENTIFIER ({ x509_extusage_note_purpose })
@@ -37,6 +37,17 @@ enum pkey_id_type {
PKEY_ID_TYPE__LAST
};
+enum pkey_usage_restriction {
+ PKEY_USAGE_NOT_SPECIFIED,
+ PKEY_RESTRICTED_USAGE,
+ PKEY_RESTRICTED_TO_OTHER,
+ PKEY_RESTRICTED_TO_MODULE_SIGNING,
+ PKEY_RESTRICTED_TO_FIRMWARE_SIGNING,
+ PKEY_RESTRICTED_TO_KEXEC_SIGNING,
+ PKEY_RESTRICTED_TO_KEY_SIGNING,
+ NR__PKEY_USAGE_RESTRICTION
+};
+
extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
/*
@@ -52,6 +63,7 @@ struct public_key {
#define PKEY_CAN_DECRYPT 0x02
#define PKEY_CAN_SIGN 0x04
#define PKEY_CAN_VERIFY 0x08
+ enum pkey_usage_restriction usage_restriction : 8;
enum pkey_algo pkey_algo : 8;
enum pkey_id_type id_type : 8;
union {
@@ -31,6 +31,9 @@ struct asymmetric_key_subtype {
/* Describe a key of this subtype for /proc/keys */
void (*describe)(const struct key *key, struct seq_file *m);
+ /* Describe capabilities/restrictions of a key of this subtype */
+ void (*describe_caps)(const struct key *key, struct seq_file *m);
+
/* Destroy a key of this subtype */
void (*destroy)(void *payload);
@@ -90,6 +90,9 @@ enum OID {
/* Signing */
OID_firmwareName, /* 1.3.6.1.4.1.2312.99.1 */
+ OID_firmwareSigningOnlyKey, /* 1.3.6.1.4.1.2312.99.2 */
+ OID_moduleSigningOnlyKey, /* 1.3.6.1.4.1.2312.99.3 */
+ OID_kexecSigningOnlyKey, /* 1.3.6.1.4.1.2312.99.4 */
OID__NR
};
@@ -239,6 +239,7 @@ x509.genkey:
@echo >>x509.genkey "keyUsage=digitalSignature"
@echo >>x509.genkey "subjectKeyIdentifier=hash"
@echo >>x509.genkey "authorityKeyIdentifier=keyid"
+ @echo >>x509.genkey "extendedKeyUsage=critical,1.3.6.1.4.1.2312.99.3"
endif
$(eval $(call config_filename,MODULE_SIG_KEY))
@@ -115,6 +115,7 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
size_t ret;
int count;
+ buffer[0] = 0;
if (v >= end)
return -EBADMSG;