■ はじめに
https://blogs.yahoo.co.jp/dk521123/37097725.html
で使用した以下のメソッド
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ X509Certificate.getIssuerX500Principal()
+ X509Certificate.getSubjectX500Principal()
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
の戻り値 X500Principal が思った以上にメソッドが少なく、
例えば、「一般名 / CN(Common Name)」だけ個別に取得したくてもできない。
そこで、CNやOUなどの値を個別に扱えるように、自作してみた
■ サンプル
DistinguishedNameType.java
import java.text.MessageFormat;
import java.util.Map;
import java.util.TreeMap;
/**
* 識別名(DN: Distinguished Name)タイプ.
*
* @see https://msdn.microsoft.com/en-us/library/aa366101(v=vs.85).aspx
* @see http://www.atmarkit.co.jp/ait/articles/0612/23/news012.html
* @see https://docs.oracle.com/cd/E19146-01/820-0875/geezw/index.html
*/
public enum DistinguishedNameType implements Comparable<DistinguishedNameType> {
/** 一般名 / CN(Common Name). */
COMMON_NAME("CN"),
/** 部門名 / OU(Organizational Unit). */
ORGANIZATIONAL_UNIT("OU"),
/** 組織名 / O(Organization). */
ORGANIZATION("O"),
/** ストリート名 / STREET(Street). */
STREET("STREET"),
/** 市区町村名 / L(Locality). */
LOCALITY("L"),
/** 都道府県名 / ST(state Or Province Name). */
STATE_OR_PROVINCE_NAME("ST"),
/** 都道府県名 / S(State). */
STATE("S"),
/** 国名 / C(Country). */
COUNTRY("C"),
/** ドメイン / DC( Domain Component). */
DOMAIN_COMPONENT("DC"),
/** ユーザID / UID(user id). */
USER_ID("UID"),
/** E-mail / E(E-mail). */
EMAIL("E"),
/** その他. */
OTHERS("");
/** フォーマット. */
private static final String FORMAT = "{0} = {1}";
/** 改行. */
private static final String NEW_LINE = System.getProperty("line.separator");
/** 変換マッパー. */
private static Map<String, DistinguishedNameType> convertMapper;
/** コード. */
private String code;
static {
convertMapper = new TreeMap<String, DistinguishedNameType>();
for (DistinguishedNameType type : DistinguishedNameType.values()) {
convertMapper.put(type.getCode(), type);
}
}
/**
* コンストラクタ.
*
* @param code
* コード
*/
private DistinguishedNameType(String code) {
this.code = code;
}
/**
* コードを取得する.
*
* @return コード
*/
public String getCode() {
return this.code;
}
/**
* X.500 識別名のMap化.
* @param targetValue RFC 2253 で定義された形式で、X.500 識別名の文字列形式
* @return X.500 識別名のMap形式
* @see https://docs.oracle.com/javase/jp/6/api/javax/security/auth/x500/X500Principal.html#getName()
* @see https://www.ipa.go.jp/security/rfc/RFC2253JA.html
*/
public static Map<DistinguishedNameType, String> parse(String targetValue) {
if (targetValue == null) {
return null;
}
Map<DistinguishedNameType, String> returnValues = new TreeMap<DistinguishedNameType, String>();
String[] attributes = targetValue.split("(?<!\\\\),");
for (String attribute : attributes) {
String[] parts = attribute.split("(?<!\\\\)=");
String type = parts[0];
if (type == null || type.isEmpty() || !convertMapper.containsKey(type)) {
String value = returnValues.get(DistinguishedNameType.OTHERS);
if (value == null) {
returnValues.put(DistinguishedNameType.OTHERS, attribute);
} else {
returnValues.put(DistinguishedNameType.OTHERS, value + NEW_LINE + attribute);
}
} else {
if (parts[1] != null) {
DistinguishedNameType targetType = convertMapper.get(type);
// 「,」「\」がエスケープされている(「\,」「\\」)ので、それを取り除く必要がある
String value = parts[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
returnValues.put(targetType, value);
}
}
}
return returnValues;
}
/**
* 文字列化.
* @param targetValue RFC 2253 で定義された形式で、X.500 識別名の文字列形式
* @return テキストデータ
* @see https://docs.oracle.com/javase/jp/6/api/javax/security/auth/x500/X500Principal.html#getName()
* @see https://www.ipa.go.jp/security/rfc/RFC2253JA.html
*/
public static String toString(String targetValue) {
Map<DistinguishedNameType, String> targetMaps = DistinguishedNameType.parse(targetValue);
return DistinguishedNameType.toString(targetMaps);
}
/**
* 文字列化.
* @param targetMaps X.500 識別名のMap形式
* @return テキストデータ
*/
public static String toString(Map<DistinguishedNameType, String> targetMaps) {
if (targetMaps == null || targetMaps.isEmpty()) {
return "";
}
StringBuilder returnValue = new StringBuilder();
int index = 0;
for (Map.Entry<DistinguishedNameType, String> map : targetMaps.entrySet()) {
if (index != 0) {
returnValue.append(NEW_LINE);
}
DistinguishedNameType targetType = map.getKey();
if (DistinguishedNameType.OTHERS.equals(targetType)) {
returnValue.append(map.getValue());
} else {
returnValue.append(MessageFormat.format(FORMAT, map.getKey().getCode(), map.getValue()));
}
index++;
}
return returnValue.toString();
}
}
呼び出し側
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Map;
public class Main {
public static void main(String[] args) {
char[] keyPasswords = "changeit".toCharArray();
try (FileInputStream fileInputStream = new FileInputStream("./etc/sample.keystore")) {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(fileInputStream, keyPasswords);
Enumeration<String> aliases = keystore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate certificate = keystore.getCertificate(alias);
if (certificate.getType().equals("X.509")) {
X509Certificate x509Certificate = (X509Certificate) certificate;
String issuerValue = x509Certificate.getIssuerX500Principal().getName();
Map<DistinguishedNameType, String> issuerParams = DistinguishedNameType.parse(issuerValue);
print(issuerParams);
String subjectValue = x509Certificate.getSubjectX500Principal().getName();
Map<DistinguishedNameType, String> subjectParams = DistinguishedNameType.parse(subjectValue);
print(subjectParams);
}
}
System.out.println("Done...");
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void print(Map<DistinguishedNameType, String> params) {
params.forEach((key, value) -> {
System.out.println(key.getCode() + " " + value);
});
}
}
./etc/sample.keystore
https://blogs.yahoo.co.jp/dk521123/36518468.html
を参考に。。。
試験用キーストアファイル
"%JAVA_HOME%\bin\keytool" -genkey -alias sample -keyalg RSA -keypass changeit -storepass changeit -keystore sample.keystore -validity 3650