Attribute certificate printing functions

Add functions to print an attribute certificate.  Several
attribute value types defined by the RFC 5755 specification
are multi-field values (i.e ASN1_SEQUENCE rather than an ASN1_STRING
or similar format).  Currently those values are printed using
`ASN1_item_print`.  A more user-friendly output mechanism (maybe
similar to the i2r_ functions used for X509 extensions) could be
added in future.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15857)
This commit is contained in:
Damian Hobson-Garcia 2023-06-30 17:44:29 -04:00 committed by Matt Caswell
parent 9e1a8b5ecc
commit 6b167313f4
6 changed files with 410 additions and 1 deletions

View file

@ -16,7 +16,7 @@ SOURCE[../../libcrypto]=\
pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_no_rev_avail.c \
v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \
x509_acert.c x509aset.c
x509_acert.c x509aset.c t_acert.c
IF[{- !$disabled{'deprecated-3.0'} -}]
SOURCE[../../libcrypto]=x509type.c

285
crypto/x509/t_acert.c Normal file
View file

@ -0,0 +1,285 @@
/*
* Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/buffer.h>
#include <openssl/bn.h>
#include <openssl/objects.h>
#include <openssl/x509_acert.h>
static int print_attribute(BIO *bp, X509_ATTRIBUTE *a)
{
ASN1_OBJECT *aobj;
int i, j, count;
int ret = 0;
aobj = X509_ATTRIBUTE_get0_object(a);
if (BIO_printf(bp, "%12s", "") <= 0)
goto err;
if ((j = i2a_ASN1_OBJECT(bp, aobj)) <= 0)
goto err;
count = X509_ATTRIBUTE_count(a);
if (count == 0) {
ERR_raise(ERR_LIB_X509, X509_R_INVALID_ATTRIBUTES);
goto err;
}
if (j < 25 && (BIO_printf(bp, "%*s", 25 - j, " ") <= 0))
goto err;
if (BIO_puts(bp, ":") <= 0)
goto err;
for (i = 0; i < count; i++) {
ASN1_TYPE *at;
int type;
ASN1_BIT_STRING *bs;
at = X509_ATTRIBUTE_get0_type(a, i);
type = at->type;
switch (type) {
case V_ASN1_PRINTABLESTRING:
case V_ASN1_T61STRING:
case V_ASN1_NUMERICSTRING:
case V_ASN1_UTF8STRING:
case V_ASN1_IA5STRING:
bs = at->value.asn1_string;
if (BIO_write(bp, (char *)bs->data, bs->length) != bs->length)
goto err;
if (BIO_puts(bp, "\n") <= 0)
goto err;
break;
case V_ASN1_SEQUENCE:
if (BIO_puts(bp, "\n") <= 0)
goto err;
ASN1_parse_dump(bp, at->value.sequence->data,
at->value.sequence->length, i, 1);
break;
default:
if (BIO_printf(bp, "unable to print attribute of type 0x%X\n",
type) < 0)
goto err;
break;
}
}
ret = 1;
err:
return ret;
}
int X509_ACERT_print_ex(BIO *bp, X509_ACERT *x, unsigned long nmflags,
unsigned long cflag)
{
int i;
char mlch = ' ';
if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
mlch = '\n';
}
if ((cflag & X509_FLAG_NO_HEADER) == 0) {
if (BIO_printf(bp, "Attribute Certificate:\n") <= 0)
goto err;
if (BIO_printf(bp, "%4sData:\n", "") <= 0)
goto err;
}
if ((cflag & X509_FLAG_NO_VERSION) == 0) {
long l;
l = X509_ACERT_get_version(x);
if (l == X509_ACERT_VERSION_2) {
if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1,
(unsigned long)l) <= 0)
goto err;
} else {
if (BIO_printf(bp, "%8sVersion: Unknown (%ld)\n", "", l) <= 0)
goto err;
}
}
if ((cflag & X509_FLAG_NO_SERIAL) == 0) {
const ASN1_INTEGER *serial;
serial = X509_ACERT_get0_serialNumber(x);
if (BIO_printf(bp, "%8sSerial Number: ", "") <= 0)
goto err;
if (i2a_ASN1_INTEGER(bp, serial) <= 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
if ((cflag & X509_FLAG_NO_SUBJECT) == 0) {
const GENERAL_NAMES *holderEntities;
const OSSL_ISSUER_SERIAL *holder_bcid;
const X509_NAME *holderIssuer = NULL;
if (BIO_printf(bp, "%8sHolder:\n", "") <= 0)
goto err;
holderEntities = X509_ACERT_get0_holder_entityName(x);
if (holderEntities != NULL) {
for (i = 0; i < sk_GENERAL_NAME_num(holderEntities); i++) {
GENERAL_NAME *entity;
entity = sk_GENERAL_NAME_value(holderEntities, i);
if (BIO_printf(bp, "%12sName:%c", "", mlch) <= 0)
goto err;
if (GENERAL_NAME_print(bp, entity) <= 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
}
if ((holder_bcid = X509_ACERT_get0_holder_baseCertId(x)) != NULL)
holderIssuer = OSSL_ISSUER_SERIAL_get0_issuer(holder_bcid);
if (holderIssuer != NULL) {
const ASN1_INTEGER *holder_serial;
const ASN1_BIT_STRING *iuid;
if (BIO_printf(bp, "%12sIssuer:%c", "", mlch) <= 0)
goto err;
if (X509_NAME_print_ex(bp, holderIssuer, 0, nmflags) <= 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
if (BIO_printf(bp, "%12sSerial: ", "") <= 0)
goto err;
holder_serial = OSSL_ISSUER_SERIAL_get0_serial(holder_bcid);
if (i2a_ASN1_INTEGER(bp, holder_serial) <= 0)
goto err;
iuid = OSSL_ISSUER_SERIAL_get0_issuerUID(holder_bcid);
if (iuid != NULL) {
if (BIO_printf(bp, "%12sIssuer UID: ", "") <= 0)
goto err;
if (X509_signature_dump(bp, iuid, 24) <= 0)
goto err;
}
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
}
if ((cflag & X509_FLAG_NO_ISSUER) == 0) {
const X509_NAME *issuer;
if (BIO_printf(bp, "%8sIssuer:%c", "", mlch) <= 0)
goto err;
issuer = X509_ACERT_get0_issuerName(x);
if (issuer) {
if (X509_NAME_print_ex(bp, issuer, 0, nmflags) < 0)
goto err;
} else {
if (BIO_printf(bp, "Unsupported Issuer Type") <= 0)
goto err;
}
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
if ((cflag & X509_FLAG_NO_VALIDITY) == 0) {
if (BIO_printf(bp, "%8sValidity\n", "") <= 0)
goto err;
if (BIO_printf(bp, "%12sNot Before: ", "") <= 0)
goto err;
if (ASN1_GENERALIZEDTIME_print(bp, X509_ACERT_get0_notBefore(x)) == 0)
goto err;
if (BIO_printf(bp, "\n%12sNot After : ", "") <= 0)
goto err;
if (ASN1_GENERALIZEDTIME_print(bp, X509_ACERT_get0_notAfter(x)) == 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
if ((cflag & X509_FLAG_NO_ATTRIBUTES) == 0) {
if (BIO_printf(bp, "%8sAttributes:\n", "") <= 0)
goto err;
if (X509_ACERT_get_attr_count(x) == 0) {
if (BIO_printf(bp, "%12s(none)\n", "") <= 0)
goto err;
} else {
for (i = 0; i < X509_ACERT_get_attr_count(x); i++) {
if (print_attribute(bp, X509_ACERT_get_attr(x, i)) == 0)
goto err;
}
}
}
if ((cflag & X509_FLAG_NO_EXTENSIONS) == 0) {
const STACK_OF(X509_EXTENSION) *exts;
exts = X509_ACERT_get0_extensions(x);
if (exts != NULL) {
if (BIO_printf(bp, "%8sExtensions:\n", "") <= 0)
goto err;
for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ex;
int critical;
ex = sk_X509_EXTENSION_value(exts, i);
if (BIO_printf(bp, "%12s", "") <= 0)
goto err;
obj = X509_EXTENSION_get_object(ex);
if (i2a_ASN1_OBJECT(bp, obj) <= 0)
goto err;
critical = X509_EXTENSION_get_critical(ex);
if (BIO_printf(bp, ": %s\n", critical ? "critical" : "") <= 0)
goto err;
if (X509V3_EXT_print(bp, ex, cflag, 20) <= 0) {
if (BIO_printf(bp, "%16s", "") <= 0)
goto err;
if (ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex)) <= 0)
goto err;
}
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
}
}
}
if ((cflag & X509_FLAG_NO_SIGDUMP) == 0) {
const X509_ALGOR *sig_alg;
const ASN1_BIT_STRING *sig;
X509_ACERT_get0_signature(x, &sig, &sig_alg);
if (X509_signature_print(bp, sig_alg, sig) <= 0)
return 0;
}
return 1;
err:
ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
return 0;
}
int X509_ACERT_print(BIO *bp, X509_ACERT *x)
{
return X509_ACERT_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
}

View file

@ -2803,6 +2803,10 @@ DEPEND[html/man3/X509_ACERT_get0_holder_baseCertId.html]=man3/X509_ACERT_get0_ho
GENERATE[html/man3/X509_ACERT_get0_holder_baseCertId.html]=man3/X509_ACERT_get0_holder_baseCertId.pod
DEPEND[man/man3/X509_ACERT_get0_holder_baseCertId.3]=man3/X509_ACERT_get0_holder_baseCertId.pod
GENERATE[man/man3/X509_ACERT_get0_holder_baseCertId.3]=man3/X509_ACERT_get0_holder_baseCertId.pod
DEPEND[html/man3/X509_ACERT_print_ex.html]=man3/X509_ACERT_print_ex.pod
GENERATE[html/man3/X509_ACERT_print_ex.html]=man3/X509_ACERT_print_ex.pod
DEPEND[man/man3/X509_ACERT_print_ex.3]=man3/X509_ACERT_print_ex.pod
GENERATE[man/man3/X509_ACERT_print_ex.3]=man3/X509_ACERT_print_ex.pod
DEPEND[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod
GENERATE[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod
DEPEND[man/man3/X509_ALGOR_dup.3]=man3/X509_ALGOR_dup.pod
@ -3636,6 +3640,7 @@ html/man3/UI_new.html \
html/man3/X509V3_get_d2i.html \
html/man3/X509V3_set_ctx.html \
html/man3/X509_ACERT_get0_holder_baseCertId.html \
html/man3/X509_ACERT_print_ex.html \
html/man3/X509_ALGOR_dup.html \
html/man3/X509_ATTRIBUTE.html \
html/man3/X509_CRL_get0_by_serial.html \
@ -4282,6 +4287,7 @@ man/man3/UI_new.3 \
man/man3/X509V3_get_d2i.3 \
man/man3/X509V3_set_ctx.3 \
man/man3/X509_ACERT_get0_holder_baseCertId.3 \
man/man3/X509_ACERT_print_ex.3 \
man/man3/X509_ALGOR_dup.3 \
man/man3/X509_ATTRIBUTE.3 \
man/man3/X509_CRL_get0_by_serial.3 \

View file

@ -0,0 +1,112 @@
=pod
=head1 NAME
X509_ACERT_print_ex, X509_ACERT_print
- X509_ACERT printing routines
=head1 SYNOPSIS
#include <openssl/x509_acert.h>
int X509_ACERT_print(BIO *bp, X509_ACERT *acert);
int X509_ACERT_print_ex(BIO *bp, X509_ACERT *acert, unsigned long nmflags,
unsigned long cflag);
=head1 DESCRIPTION
X509_ACERT_print_ex() prints a human readable version of the attribute
certificate I<acert> to BIO I<bp>.
The following data contained in the attribute certificate is printed
in order:
=over 4
=item *
The header text "Attribute certificate:" and "Data:" (X509_FLAG_NO_HEADER)
= item *
The attribute certificate version number as defined by the standard,
followed in parentheses by the value contained in the version field in
hexadecimal notation. If the version number is not a valid value according
to the specification, only the raw value is printed.
See X509_ACERT_get_version(3) for details. (X509_FLAG_NO_VERSION)
= item *
The serial number of the attribute certificate (X509_FLAG_NO_SERIAL)
= item *
The identity of the holder of the attribute certificate. If the
holder issuer name is present, the first GENERAL_NAME
returned by X509_ACERT_get0_holder_entityName() is printed.
If the holder baseCertificateId is present, the issuer name
(printed with X509_NAME_print_ex) and serial number of the
holder's certificate are displayed. (X509_FLAG_NO_SUBJECT)
= item *
The name of the attribute certificate issuer as returned from
X509_ACERT_get0_issuerName() and printed using X509_NAME_print_ex().
(X509_FLAG_NO_ISSUER)
= item *
The period of validity between the times returned from X509_ACERT_get0_notBefore()
and X509_ACERT_get0_notAfter(). The values are printed as a generalized times
using ASN1_GENERALIZEDTIME_print(). (X509_FLAG_NO_VALIDITY)
= item *
The list of attributes contained in the attribute certificate.
The attribute type is printed with i2a_ASN1_OBJECT(). String valued
attributes are printed as raw string data. ASN1 encoded values are
printed with ASN1_parse_dump(). (X509_FLAG_NO_ATTRIBUTES)
= item *
All X.509 extensions contained in the attribute certificate. (X509_FLAG_NO_EXTENSIONS)
= item *
The signature is printed with X509_signature_print(). (X509_FLAG_NO_SIGDUMP)
If I<cflag> is specifies as X509_FLAG_COMPAT, all of the above data in the
attribute certificate will be printed.
The I<nmflags> flag determines the format used to output all fields printed using
X509_NAME_print_ex(). See L<X509_NAME_print_ex(3)> for details.
X509_ACERT_print() is equivalent to calling X509_ACERT_print_ex() with the
I<nmflags> and I<cflags> set to XN_FLAG_COMPAT and X509_FLAG_COMPAT
respectively.
=back
=head1 RETURN VALUES
X509_ACERT_print_ex() X509_ACERT_print() return 1 for
success and 0 for failure.
=head1 SEE ALSO
L<X509_NAME_print_ex(3)>
=head1 HISTORY
X509_ACERT_print() and X509_ACERT_print_ex() were added in OpenSSL 3.4.
=head1 COPYRIGHT
Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -62,6 +62,10 @@ const ASN1_TIME *X509_ACERT_get0_notBefore(const X509_ACERT *x);
const ASN1_TIME *X509_ACERT_get0_notAfter(const X509_ACERT *x);
const ASN1_BIT_STRING *X509_ACERT_get0_issuerUID(const X509_ACERT *x);
int X509_ACERT_print(BIO *bp, X509_ACERT *x);
int X509_ACERT_print_ex(BIO *bp, X509_ACERT *x, unsigned long nmflags,
unsigned long cflag);
# define OSSL_OBJECT_DIGEST_INFO_PUBLIC_KEY 0
# define OSSL_OBJECT_DIGEST_INFO_PUBLIC_KEY_CERT 1
# define OSSL_OBJECT_DIGEST_INFO_OTHER 2 /* must not be used in RFC 5755 profile */

View file

@ -5601,3 +5601,5 @@ OSSL_ISSUER_SERIAL_get0_issuerUID ? 3_4_0 EXIST::FUNCTION:
OSSL_ISSUER_SERIAL_set1_issuer ? 3_4_0 EXIST::FUNCTION:
OSSL_ISSUER_SERIAL_set1_serial ? 3_4_0 EXIST::FUNCTION:
OSSL_ISSUER_SERIAL_set1_issuerUID ? 3_4_0 EXIST::FUNCTION:
X509_ACERT_print ? 3_4_0 EXIST::FUNCTION:
X509_ACERT_print_ex ? 3_4_0 EXIST::FUNCTION: