Skip to content

Commit

Permalink
zlint PR 825
Browse files Browse the repository at this point in the history
  • Loading branch information
mtgag committed Apr 9, 2024
1 parent 09f68d7 commit d91f1a3
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;

import de.mtg.jzlint.EffectiveDate;
Expand All @@ -30,33 +37,16 @@ public class MailboxAddressShallContainAnRfc822Name implements JavaLint {
public LintResult execute(X509Certificate certificate) {

try {
List<String> subjectEmails = new ArrayList<>();

List<AttributeTypeAndValue> commonName = Utils.getSubjectDNNameComponent(certificate, X509ObjectIdentifiers.commonName.getId());

for (AttributeTypeAndValue attributeTypeAndValue : commonName) {
String email = attributeTypeAndValue.getValue().toString();
if (SMIMEUtils.isValidEmailAddress(email)) {
subjectEmails.add(email);
}
}
List<AttributeTypeAndValue> dnEmails = Utils.getSubjectDNNameComponent(certificate, BCStyle.EmailAddress.getId());
for (AttributeTypeAndValue attributeTypeAndValue : dnEmails) {
String email = attributeTypeAndValue.getValue().toString();
if (SMIMEUtils.isValidEmailAddress(email)) {
subjectEmails.add(email);
}
}

List<String> dirNames = Utils.getDirNames(certificate);
subjectEmails.addAll(dirNames);
List<String> subjectEmails = getMailboxAddresses(certificate);

List<String> sanEmails = Utils.getEmails(certificate);
sanEmails.addAll(SMIMEUtils.getSmtpUTF8Mailboxes(certificate));

for (String subjectEmail : subjectEmails) {
if (!sanEmails.contains(subjectEmail)) {
return LintResult.of(Status.ERROR, "all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear");
return LintResult.of(Status.ERROR,
"all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear");
}
}

Expand All @@ -70,7 +60,62 @@ public LintResult execute(X509Certificate certificate) {

@Override
public boolean checkApplies(X509Certificate certificate) {
return SMIMEUtils.isSMIMEBRSubscriberCertificate(certificate);

if (!SMIMEUtils.isSMIMEBRSubscriberCertificate(certificate)) {
return false;
}

List<String> mailboxAddresses = getMailboxAddresses(certificate);

return !mailboxAddresses.isEmpty();

}

private List<String> getMailboxAddresses(X509Certificate certificate) {
List<String> mailboxAddresses = getMailboxAddressesFromName(certificate.getSubjectX500Principal().getEncoded(),
SMIMEUtils.isMailboxValidatedCertificate(certificate));

byte[] rawSAN = certificate.getExtensionValue(Extension.subjectAlternativeName.getId());

try {
if (rawSAN != null) {
GeneralNames generalNames = GeneralNames.getInstance(((ASN1OctetString) ASN1Primitive.fromByteArray(rawSAN)).getOctets());
GeneralName[] names = generalNames.getNames();
List<ASN1Encodable> generalNameList = new ArrayList<>();
Arrays.stream(names).filter(generalName -> generalName.getTagNo() == 4).map(g -> g.getName()).forEach(generalNameList::add);
for (ASN1Encodable encodable : generalNameList) {
List<String> mailboxAddressesFromName = getMailboxAddressesFromName(encodable.toASN1Primitive().getEncoded(), false);
mailboxAddresses.addAll(mailboxAddressesFromName);
}
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return mailboxAddresses;
}

private List<String> getMailboxAddressesFromName(byte[] encodedName, boolean includeCN) {
List<String> emails = new ArrayList<>();

List<AttributeTypeAndValue> commonName = Utils.getNameComponent(X509ObjectIdentifiers.commonName.getId(), encodedName);

if (includeCN) {
for (AttributeTypeAndValue attributeTypeAndValue : commonName) {
String email = attributeTypeAndValue.getValue().toString();
if (SMIMEUtils.isValidEmailAddress(email)) {
emails.add(email);
}
}
}

List<AttributeTypeAndValue> dnEmails = Utils.getNameComponent(BCStyle.EmailAddress.getId(), encodedName);
for (AttributeTypeAndValue attributeTypeAndValue : dnEmails) {
String email = attributeTypeAndValue.getValue().toString();
if (SMIMEUtils.isValidEmailAddress(email)) {
emails.add(email);
}
}
return emails;
}

}
6 changes: 1 addition & 5 deletions jzlint/src/main/java/de/mtg/jzlint/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,6 @@ public static List<String> getEmails(X509Certificate certificate) throws IOExcep
return getGeneralNameAsString(certificate, 1);
}

public static List<String> getDirNames(X509Certificate certificate) throws IOException {
return getGeneralNameAsString(certificate, 4);
}

public static List<String> getIpAddresses(X509Certificate certificate) throws IOException {

IPAddressNetwork.IPAddressGenerator generator = new IPAddressNetwork.IPAddressGenerator();
Expand Down Expand Up @@ -606,7 +602,7 @@ private static byte[] getContent(byte[] encoded) {

}

private static List<AttributeTypeAndValue> getNameComponent(String oid, byte[] encodedDN) {
public static List<AttributeTypeAndValue> getNameComponent(String oid, byte[] encodedDN) {

List<AttributeTypeAndValue> list = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ void testCase02() {
@LintTest(
name = "e_mailbox_address_shall_contain_an_rfc822_name",
filename = "smime/MailboxAddressFromSAN/WithOnlySANEmail.pem",
expectedResultStatus = Status.PASS,
certificateDescription = "pass - only contains one san:emailAddress value")
expectedResultStatus = Status.NA,
certificateDescription = "na - only contains one san:emailAddress value")
void testCase03() {
}

@LintTest(
name = "e_mailbox_address_shall_contain_an_rfc822_name",
filename = "smime/MailboxAddressFromSAN/WithOnlySANOtherName.pem",
expectedResultStatus = Status.PASS,
certificateDescription = "pass - only contains one san:otherName value")
expectedResultStatus = Status.NA,
certificateDescription = "na - only contains one san:otherName value")
void testCase04() {
}

Expand Down Expand Up @@ -92,8 +92,8 @@ void testCase10() {
@LintTest(
name = "e_mailbox_address_shall_contain_an_rfc822_name",
filename = "smime/MailboxAddressFromSAN/sponsorValidatedMultipurposePersonalNameInCN.pem",
expectedResultStatus = Status.PASS,
certificateDescription = "pass - subject:commonName is personal name, san:emailAddress contains an email")
expectedResultStatus = Status.NA,
certificateDescription = "na - subject:commonName is personal name, san:emailAddress contains an email")
void testCase11() {
}

Expand Down

0 comments on commit d91f1a3

Please sign in to comment.