All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.tls.CertificateRequest Maven / Gradle / Ivy

The newest version!
package org.bouncycastle.tls;

import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.util.Arrays;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;

/**
 * Parsing and encoding of a CertificateRequest struct from RFC 4346:
 * 
 * struct {
 *     ClientCertificateType certificate_types<1..2^8-1>;
 *     DistinguishedName certificate_authorities<3..2^16-1>;
 * } CertificateRequest;
 * 
* Updated for RFC 5246: *
 * struct {
 *     ClientCertificateType certificate_types<1..2^8-1>;
 *     SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>;
 *     DistinguishedName certificate_authorities<0..2^16-1>;
 * } CertificateRequest;
 * 
* Revised for RFC 8446: *
 * struct {
 *     opaque certificate_request_context<0..2^8-1>;
 *     Extension extensions<2..2^16-1>;
 * } CertificateRequest;
 * 
* * @see ClientCertificateType * @see X500Name */ public class CertificateRequest { private static Vector checkSupportedSignatureAlgorithms(Vector supportedSignatureAlgorithms, short alertDescription) throws IOException { if (null == supportedSignatureAlgorithms) { throw new TlsFatalAlert(alertDescription, "'signature_algorithms' is required"); } return supportedSignatureAlgorithms; } protected final byte[] certificateRequestContext; protected final short[] certificateTypes; protected final Vector supportedSignatureAlgorithms; protected final Vector supportedSignatureAlgorithmsCert; protected final Vector certificateAuthorities; /** * @param certificateTypes see {@link ClientCertificateType} for valid constants. * @param certificateAuthorities a {@link Vector} of {@link X500Name}. */ public CertificateRequest(short[] certificateTypes, Vector supportedSignatureAlgorithms, Vector certificateAuthorities) { this(null, certificateTypes, supportedSignatureAlgorithms, null, certificateAuthorities); } // TODO[tls13] Prefer to manage the certificateRequestContext internally only? public CertificateRequest(byte[] certificateRequestContext, Vector supportedSignatureAlgorithms, Vector supportedSignatureAlgorithmsCert, Vector certificateAuthorities) throws IOException { /* * TODO[tls13] Removed certificateTypes, added certificate_request_context, added extensions * (required: signature_algorithms, optional: status_request, signed_certificate_timestamp, * certificate_authorities, oid_filters, signature_algorithms_cert) */ this(certificateRequestContext, null, checkSupportedSignatureAlgorithms(supportedSignatureAlgorithms, AlertDescription.internal_error), supportedSignatureAlgorithmsCert, certificateAuthorities); } private CertificateRequest(byte[] certificateRequestContext, short[] certificateTypes, Vector supportedSignatureAlgorithms, Vector supportedSignatureAlgorithmsCert, Vector certificateAuthorities) { if (null != certificateRequestContext && !TlsUtils.isValidUint8(certificateRequestContext.length)) { throw new IllegalArgumentException("'certificateRequestContext' cannot be longer than 255"); } if (null != certificateTypes && (certificateTypes.length < 1 || !TlsUtils.isValidUint8(certificateTypes.length))) { throw new IllegalArgumentException("'certificateTypes' should have length from 1 to 255"); } this.certificateRequestContext = TlsUtils.clone(certificateRequestContext); this.certificateTypes = certificateTypes; this.supportedSignatureAlgorithms = supportedSignatureAlgorithms; this.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert; this.certificateAuthorities = certificateAuthorities; } public byte[] getCertificateRequestContext() { return TlsUtils.clone(certificateRequestContext); } /** * @return an array of certificate types * @see ClientCertificateType */ public short[] getCertificateTypes() { return certificateTypes; } /** * @return a {@link Vector} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2). */ public Vector getSupportedSignatureAlgorithms() { return supportedSignatureAlgorithms; } /** * @return an optional {@link Vector} of {@link SignatureAndHashAlgorithm}. May be non-null from * TLS 1.3 onwards. */ public Vector getSupportedSignatureAlgorithmsCert() { return supportedSignatureAlgorithmsCert; } /** * @return a {@link Vector} of {@link X500Name} */ public Vector getCertificateAuthorities() { return certificateAuthorities; } public boolean hasCertificateRequestContext(byte[] certificateRequestContext) { return Arrays.areEqual(this.certificateRequestContext, certificateRequestContext); } /** * Encode this {@link CertificateRequest} to an {@link OutputStream}. * * @param context * the {@link TlsContext} of the current connection. * @param output the {@link OutputStream} to encode to. * @throws IOException */ public void encode(TlsContext context, OutputStream output) throws IOException { final ProtocolVersion negotiatedVersion = context.getServerVersion(); final boolean isTLSv12 = TlsUtils.isTLSv12(negotiatedVersion); final boolean isTLSv13 = TlsUtils.isTLSv13(negotiatedVersion); if (isTLSv13 != (null != certificateRequestContext) || isTLSv13 != (null == certificateTypes) || isTLSv12 != (null != supportedSignatureAlgorithms) || (!isTLSv13 && (null != supportedSignatureAlgorithmsCert))) { throw new IllegalStateException(); } if (isTLSv13) { TlsUtils.writeOpaque8(certificateRequestContext, output); Map extensions = new LinkedHashMap<>(); TlsExtensionsUtils.addSignatureAlgorithmsExtension(extensions, supportedSignatureAlgorithms); if (null != supportedSignatureAlgorithmsCert) { TlsExtensionsUtils.addSignatureAlgorithmsCertExtension(extensions, supportedSignatureAlgorithmsCert); } if (null != certificateAuthorities) { TlsExtensionsUtils.addCertificateAuthoritiesExtension(extensions, certificateAuthorities); } byte[] extEncoding = TlsProtocol.writeExtensionsData(extensions); TlsUtils.writeOpaque16(extEncoding, output); return; } TlsUtils.writeUint8ArrayWithUint8Length(certificateTypes, output); if (isTLSv12) { // TODO Check whether SignatureAlgorithm.anonymous is allowed here TlsUtils.encodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, output); } if (certificateAuthorities == null || certificateAuthorities.isEmpty()) { TlsUtils.writeUint16(0, output); } else { Vector derEncodings = new Vector(certificateAuthorities.size()); int totalLength = 0; for (int i = 0; i < certificateAuthorities.size(); ++i) { X500Name certificateAuthority = (X500Name)certificateAuthorities.elementAt(i); byte[] derEncoding = certificateAuthority.getEncoded(ASN1Encoding.DER); derEncodings.addElement(derEncoding); totalLength += derEncoding.length + 2; } TlsUtils.checkUint16(totalLength); TlsUtils.writeUint16(totalLength, output); for (int i = 0; i < derEncodings.size(); ++i) { byte[] derEncoding = (byte[])derEncodings.elementAt(i); TlsUtils.writeOpaque16(derEncoding, output); } } } /** * Parse a {@link CertificateRequest} from an {@link InputStream}. * * @param context * the {@link TlsContext} of the current connection. * @param input * the {@link InputStream} to parse from. * @return a {@link CertificateRequest} object. * @throws IOException */ public static CertificateRequest parse(TlsContext context, InputStream input) throws IOException { final ProtocolVersion negotiatedVersion = context.getServerVersion(); final boolean isTLSv13 = TlsUtils.isTLSv13(negotiatedVersion); if (isTLSv13) { byte[] certificateRequestContext = TlsUtils.readOpaque8(input); /* * TODO[tls13] required: signature_algorithms; optional: status_request, * signed_certificate_timestamp, certificate_authorities, oid_filters, * signature_algorithms_cert */ byte[] extEncoding = TlsUtils.readOpaque16(input); Map extensions = TlsProtocol.readExtensionsData13(HandshakeType.certificate_request, extEncoding); Vector supportedSignatureAlgorithms = checkSupportedSignatureAlgorithms( TlsExtensionsUtils.getSignatureAlgorithmsExtension(extensions), AlertDescription.missing_extension); Vector supportedSignatureAlgorithmsCert = TlsExtensionsUtils .getSignatureAlgorithmsCertExtension(extensions); Vector certificateAuthorities = TlsExtensionsUtils.getCertificateAuthoritiesExtension(extensions); return new CertificateRequest(certificateRequestContext, supportedSignatureAlgorithms, supportedSignatureAlgorithmsCert, certificateAuthorities); } final boolean isTLSv12 = TlsUtils.isTLSv12(negotiatedVersion); short[] certificateTypes = TlsUtils.readUint8ArrayWithUint8Length(input, 1); Vector supportedSignatureAlgorithms = null; if (isTLSv12) { supportedSignatureAlgorithms = TlsUtils.parseSupportedSignatureAlgorithms(input); } Vector certificateAuthorities = null; { byte[] certAuthData = TlsUtils.readOpaque16(input); if (certAuthData.length > 0) { certificateAuthorities = new Vector(); ByteArrayInputStream bis = new ByteArrayInputStream(certAuthData); do { byte[] derEncoding = TlsUtils.readOpaque16(bis, 1); ASN1Primitive asn1 = TlsUtils.readASN1Object(derEncoding); X500Name ca = X500Name.getInstance(asn1); TlsUtils.requireDEREncoding(ca, derEncoding); certificateAuthorities.addElement(ca); } while (bis.available() > 0); } } return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy