diff options
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CertificateRequest.java')
-rw-r--r-- | libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CertificateRequest.java | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CertificateRequest.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CertificateRequest.java new file mode 100644 index 000000000..a4e5bf9e8 --- /dev/null +++ b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CertificateRequest.java @@ -0,0 +1,164 @@ +package org.spongycastle.crypto.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.x500.X500Name; + +/** + * Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346. + * <p/> + * <pre> + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * DistinguishedName certificate_authorities<3..2^16-1>; + * } CertificateRequest; + * </pre> + * + * @see ClientCertificateType + * @see X500Name + */ +public class CertificateRequest +{ + protected short[] certificateTypes; + protected Vector supportedSignatureAlgorithms; + protected Vector certificateAuthorities; + + /* + * TODO RFC 5264 7.4.4 A list of the hash/signature algorithm pairs that the server is able to + * verify, listed in descending order of preference. + */ + + /** + * @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.certificateTypes = certificateTypes; + this.supportedSignatureAlgorithms = supportedSignatureAlgorithms; + this.certificateAuthorities = certificateAuthorities; + } + + /** + * @return an array of certificate types + * @see {@link 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 a {@link Vector} of {@link X500Name} + */ + public Vector getCertificateAuthorities() + { + return certificateAuthorities; + } + + /** + * Encode this {@link CertificateRequest} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + if (certificateTypes == null || certificateTypes.length == 0) + { + TlsUtils.writeUint8(0, output); + } + else + { + TlsUtils.writeUint8ArrayWithUint8Length(certificateTypes, output); + } + + if (supportedSignatureAlgorithms != null) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + TlsUtils.encodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, 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; + } + + TlsUtils.checkUint16(totalLength); + TlsUtils.writeUint16(totalLength, output); + + for (int i = 0; i < derEncodings.size(); ++i) + { + byte[] encDN = (byte[])derEncodings.elementAt(i); + output.write(encDN); + } + } + } + + /** + * 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 + { + int numTypes = TlsUtils.readUint8(input); + short[] certificateTypes = new short[numTypes]; + for (int i = 0; i < numTypes; ++i) + { + certificateTypes[i] = TlsUtils.readUint8(input); + } + + Vector supportedSignatureAlgorithms = null; + if (TlsUtils.isTLSv12(context)) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + supportedSignatureAlgorithms = TlsUtils.parseSupportedSignatureAlgorithms(false, input); + } + + Vector certificateAuthorities = new Vector(); + byte[] certAuthData = TlsUtils.readOpaque16(input); + ByteArrayInputStream bis = new ByteArrayInputStream(certAuthData); + while (bis.available() > 0) + { + byte[] derEncoding = TlsUtils.readOpaque16(bis); + ASN1Primitive asn1 = TlsUtils.readDERObject(derEncoding); + certificateAuthorities.addElement(X500Name.getInstance(asn1)); + } + + return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); + } +} |