package model.csr; import annotations.Assoc; import model.asn1.ASN1Object; import model.asn1.BitString; import model.asn1.Tag; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import model.pki.AlgorithmIdentifier; import java.util.Arrays; import java.util.Collection; import java.util.stream.Stream; /** * Represents a PKCS#10 CSR. *
 *    CertificationRequest ::= SEQUENCE {
 *         certificationRequestInfo CertificationRequestInfo,
 *         signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
 *         signature          BIT STRING
 *    }
 * 
*

* A CSR is used to request a certificate from a CA, using a public key. The client encodes a CSR with * its subject name, public key, and attributes, and sign that with their private key. The private key * must match the public key encoded in the CSR. This is to prove to the CA that the client has the private * key of the requested public key. * After the CA receives the CSR, they can create a new certificate, with or without the requested subject * and attributes. That is, the requested attributes only have informational purposes, and it is the CA that * determines whether to use them. * The data in the CSR are encoded in {@link CertificationRequestInfo}. This object contains the data an * the signature. */ public class CertificationRequest extends ASN1Object { /** * All info of that CSR, excluding the signature. * It will be signed, and the signature is in

signature
. */ @Assoc(partOf = true) private final CertificationRequestInfo certificationRequestInfo; /** * The algorithm used for
signature
. */ @Assoc(partOf = true) private final AlgorithmIdentifier signatureAlgorithm; /** * The signature. */ @Assoc(partOf = true) private final BitString signature; /** * EFFECTS: Initialize the object with the given tag and parentTag, and info, signatureAlgorithm, and signature. * REQUIRES: The signature must match the public key specified in info. The algorithm must match the signature. The * fields must have correct tags as described in the class specification. */ public CertificationRequest(Tag tag, Tag parentTag, final CertificationRequestInfo certificationRequestInfo, final AlgorithmIdentifier signatureAlgorithm, final BitString signature) { super(tag, parentTag); this.certificationRequestInfo = certificationRequestInfo; this.signatureAlgorithm = signatureAlgorithm; this.signature = signature; } /** * EFFECTS: Parse input DER CSR, without verifying the signature. * Throws {@link ParseException} if the input is invalid: * - Any fields missing (info, algorithm, signature) * - Any fields having an incorrect tag (as seen in the ASN.1 definition) * - Any fields with encoding instructions that violate implicit / explicit encoding rules * - Other issues found during parsing the object, like early EOF (see {@link ASN1Object}) * MODIFIES: this, encoded */ public CertificationRequest(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); this.certificationRequestInfo = new CertificationRequestInfo(encoded, false); this.certificationRequestInfo.getTag().enforce(TAG_SEQUENCE); this.signatureAlgorithm = new AlgorithmIdentifier(encoded, false); this.signatureAlgorithm.getTag().enforce(TAG_SEQUENCE); this.signature = new BitString(encoded, false); this.signature.getTag().enforce(BitString.TAG); } /** * EFFECT: Encode that sequence into an ordered array of bytes, following the class specification. */ @Override public Byte[] encodeValueDER() { return Stream.of(Arrays.asList(certificationRequestInfo.encodeDER()), Arrays.asList(signatureAlgorithm.encodeDER()), Arrays.asList(signature.encodeDER())) .flatMap(Collection::stream) .toArray(Byte[]::new); } public CertificationRequestInfo getCertificationRequestInfo() { return certificationRequestInfo; } public AlgorithmIdentifier getSignatureAlgorithm() { return signatureAlgorithm; } public BitString getSignature() { return signature; } }