Add methods to set attributes to SMIMECSRBuilder

pull/134/head
Richard Körber 2022-06-29 19:17:22 +02:00
parent e851acd61d
commit 8d9ab54782
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
3 changed files with 117 additions and 10 deletions

View File

@ -32,6 +32,7 @@ import java.util.List;
import edu.umd.cs.findbugs.annotations.Nullable;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
@ -144,6 +145,49 @@ public class SMIMECSRBuilder {
Arrays.stream(ids).forEach(this::addIdentifier);
}
/**
* Sets an entry of the subject used for the CSR.
* <p>
* This method is meant as "expert mode" for setting attributes that are not covered
* by the other methods. It is at the discretion of the ACME server to accept this
* parameter.
*
* @param attName
* The BCStyle attribute name
* @param value
* The value
* @throws AddressException
* if a common name is added, but the value is not a valid email address.
* @since 2.14
*/
public void addValue(String attName, String value) throws AddressException {
ASN1ObjectIdentifier oid = X500Name.getDefaultStyle().attrNameToOID(requireNonNull(attName, "attribute name must not be null"));
addValue(oid, value);
}
/**
* Sets an entry of the subject used for the CSR
* <p>
* This method is meant as "expert mode" for setting attributes that are not covered
* by the other methods. It is at the discretion of the ACME server to accept this
* parameter.
*
* @param oid
* The OID of the attribute to be added
* @param value
* The value
* @throws AddressException
* if a common name is added, but the value is not a valid email address.
* @since 2.14
*/
public void addValue(ASN1ObjectIdentifier oid, String value) throws AddressException {
if (requireNonNull(oid, "OID must not be null").equals(BCStyle.CN)) {
addEmail(new InternetAddress(value));
return;
}
namebuilder.addRDN(oid, requireNonNull(value, "attribute value must not be null"));
}
/**
* Sets the organization.
* <p>

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.smime.csr;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.ByteArrayOutputStream;
@ -29,6 +30,7 @@ import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.pkcs.Attribute;
@ -144,6 +146,58 @@ public class SMIMECSRBuilderTest {
keyUsageTest(csr, KeyUsage.digitalSignature | KeyUsage.keyEncipherment);
}
/**
* Checks that addValue behaves correctly in dependence of the attributes being added.
* If a common name is set, it should be handled in the same way when it's added by
* using {@link SMIMECSRBuilder#addEmail(InternetAddress)}.
*/
@Test
public void testAddAttrValues() throws Exception {
SMIMECSRBuilder builder = new SMIMECSRBuilder();
String invAttNameExMessage = assertThrows(IllegalArgumentException.class,
() -> X500Name.getDefaultStyle().attrNameToOID("UNKNOWNATT")).getMessage();
assertThat(builder.toString()).isEqualTo(",TYPE=SIGNING_AND_ENCRYPTION");
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> new SMIMECSRBuilder().addValue((String) null, "value"))
.as("addValue(String, String)");
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> new SMIMECSRBuilder().addValue((ASN1ObjectIdentifier) null, "value"))
.as("addValue(ASN1ObjectIdentifier, String)");
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> new SMIMECSRBuilder().addValue("C", null))
.as("addValue(String, null)");
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new SMIMECSRBuilder().addValue("UNKNOWNATT", "val"))
.as("addValue(String, null)")
.withMessage(invAttNameExMessage);
assertThatExceptionOfType(AddressException.class)
.isThrownBy(() -> new SMIMECSRBuilder().addValue("CN", "invalid@example..com"))
.as("addValue(String, invalid String)");
assertThat(builder.toString()).isEqualTo(",TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue("C", "DE");
assertThat(builder.toString()).isEqualTo("C=DE,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue("E", "contact@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue("CN", "firstcn@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,CN=firstcn@example.com,EMAIL=firstcn@example.com,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue("CN", "scnd@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,CN=firstcn@example.com,EMAIL=firstcn@example.com,EMAIL=scnd@example.com,TYPE=SIGNING_AND_ENCRYPTION");
builder = new SMIMECSRBuilder();
builder.addValue(BCStyle.C, "DE");
assertThat(builder.toString()).isEqualTo("C=DE,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue(BCStyle.EmailAddress, "contact@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue(BCStyle.CN, "firstcn@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,CN=firstcn@example.com,EMAIL=firstcn@example.com,TYPE=SIGNING_AND_ENCRYPTION");
builder.addValue(BCStyle.CN, "scnd@example.com");
assertThat(builder.toString()).isEqualTo("C=DE,E=contact@example.com,CN=firstcn@example.com,EMAIL=firstcn@example.com,EMAIL=scnd@example.com,TYPE=SIGNING_AND_ENCRYPTION");
}
/**
* Checks if the S/MIME CSR contains the right parameters.
* <p>

View File

@ -33,7 +33,6 @@ import java.util.List;
import java.util.Objects;
import edu.umd.cs.findbugs.annotations.Nullable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
@ -185,13 +184,18 @@ public class CSRBuilder {
public void addIdentifiers(Identifier... ids) {
Arrays.stream(ids).forEach(this::addIdentifier);
}
/**
* Sets an entry of the subject used for the CSR
* Sets an entry of the subject used for the CSR.
* <p>
* Note that it is at the discretion of the ACME server to accept this parameter.
* @param attName The BCStyle attribute name
* @param value The value
* This method is meant as "expert mode" for setting attributes that are not covered
* by the other methods. It is at the discretion of the ACME server to accept this
* parameter.
*
* @param attName
* The BCStyle attribute name
* @param value
* The value
* @since 2.14
*/
public void addValue(String attName, String value) {
@ -200,11 +204,16 @@ public class CSRBuilder {
}
/**
* Sets an entry of the subject used for the CSR
* Sets an entry of the subject used for the CSR.
* <p>
* Note that it is at the discretion of the ACME server to accept this parameter.
* @param oid The OID of the attribute to be added
* @param value The value
* This method is meant as "expert mode" for setting attributes that are not covered
* by the other methods. It is at the discretion of the ACME server to accept this
* parameter.
*
* @param oid
* The OID of the attribute to be added
* @param value
* The value
* @since 2.14
*/
public void addValue(ASN1ObjectIdentifier oid, String value) {