CertUtilsLoader.java
6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package com.github.monkeywie.proxyee.crt;
import com.github.monkeywie.proxyee.crt.service.bc.BouncyCastleCertGenerator;
import com.github.monkeywie.proxyee.crt.spi.CertGenerator;
import com.github.monkeywie.proxyee.crt.spi.CertGeneratorInfo;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
/**
* CertUtil 的内部类.
* <p>通过 {@link CertGenerator} 让 Proxyee 不再固定依赖 BC 加密套件, 可根据需要自行指定套件的相关操作提供给 Proxyee.
*
* @author LamGC
*/
public final class CertUtilsLoader {
private final static InternalLogger log = InternalLoggerFactory.getInstance(CertUtilsLoader.class);
public final static String DEFAULT_GENERATOR_NAME = "BouncyCastle";
private final static Map<String, CertGenerator> generatorMap = new Hashtable<>();
private final static AtomicReference<String> selectionGenerator = new AtomicReference<>(DEFAULT_GENERATOR_NAME);
static {
try {
loadGenerator();
} catch (Exception e) {
// 拦截未考虑的异常以防导致类加载失败, 然后程序 Boom!
// 为保证即使加载失败也能正常运行, 在此例外加载 BC 默认加密实现(保持鲁棒性)
log.error("An uncaught exception was thrown while loading the certificate generator", e);
generatorMap.put(DEFAULT_GENERATOR_NAME, new BouncyCastleCertGenerator());
}
}
/**
* 阻止实例化本类.
*/
private CertUtilsLoader() {}
/**
* 通过 SPI 机制加载并验证证书生成器实现.
*/
private static void loadGenerator() {
ServiceLoader<CertGenerator> serviceLoader = ServiceLoader.load(CertGenerator.class);
for (CertGenerator generator : serviceLoader) {
Class<? extends CertGenerator> generatorClass = generator.getClass();
if (!generatorClass.isAnnotationPresent(CertGeneratorInfo.class)) {
log.warn("CertGeneratorInfo annotation not found for implementation class {}",
generatorClass.getName());
continue;
}
CertGeneratorInfo info = generatorClass.getAnnotation(CertGeneratorInfo.class);
String generatorName = info.name().trim();
if (generatorName.isEmpty()) {
log.warn("Implementation class {} name is empty", generatorClass.getName());
continue;
} else if (generatorMap.containsKey(generatorName)) {
CertGenerator currentGenerator = generatorMap.get(generatorName);
log.warn("A loaded implementation already exists for name {} (current implementation: {}), " +
"skipping implementation {}}",
generatorName,
currentGenerator.getClass().getName(),
generatorClass.getName());
continue;
}
generatorMap.put(generatorName, generator);
log.debug("Generator implementation loaded (Name: {}, implementation class: {})",
generatorName,
generatorClass.getName());
}
}
/**
* 设置所使用的生成器名称.
* @param generatorName 欲使用的生成器所属名称.
* @throws NoSuchElementException 如果指定名称不存在所属生成器则抛出该异常.
*/
public static void setSelectionGenerator(String generatorName) throws NoSuchElementException {
if (!generatorMap.containsKey(generatorName.trim())) {
throw new NoSuchElementException("The specified generator was not found: " + generatorName);
}
selectionGenerator.set(generatorName.trim());
}
/**
* 检查生成器是否存在并获取.
* @param name 生成器名称.
* @return 如果存在, 返回指定名称的生成器.
* @throws NullPointerException 如果 name 为 null, 则抛出 NPE.
* @throws NoSuchElementException 如果 name 指定的生成器不存在, 则抛出该异常.
*/
private static CertGenerator checkGenerateExistAndGet(String name) {
if (!generatorMap.containsKey(name)) {
// u1s1, Unchecked Exception 确实是个好东西.
throw new NoSuchElementException(
"The certificate generator with the specified name was not found: " + name);
}
return generatorMap.get(name);
}
/**
* 获取当前所选择的生成器名称.
* @return 返回指定要使用的生成器名称.
*/
public static String getCurrentSelectionGenerator() {
return selectionGenerator.get();
}
/**
* 生成服务端自签名证书.
* @param issuer 元数据(X509 Names)
* @param caPriKey 用于进行签名的 CA 私钥.
* @param caNotBefore 证书生效时间, 在这个时间之前证书也是失效的.
* @param caNotAfter 证书失效时间, 过了这个时间后证书即失效.
* @param serverPubKey 服务端证书公钥.
* @param hosts 证书所属域名.
* @return 返回指定域名所属的服务端 X509 证书.
*/
public static X509Certificate generateServerCert(String issuer, PrivateKey caPriKey, Date caNotBefore,
Date caNotAfter, PublicKey serverPubKey, String... hosts)
throws Exception {
return checkGenerateExistAndGet(selectionGenerator.get()).generateServerCert(
issuer, caPriKey, caNotBefore,
caNotAfter, serverPubKey, hosts);
}
/**
* 生成 CA 证书(自签名).
* @param subject 元数据(X509 Names)
* @param caNotBefore 证书生效时间, 在这个时间之前证书也是失效的.
* @param caNotAfter 证书失效时间, 过了这个时间后证书即失效.
* @param keyPair RSA 密钥对.
* @return 返回自签名 CA 证书.
*/
public static X509Certificate generateCaCert(String subject, Date caNotBefore,
Date caNotAfter, KeyPair keyPair) throws Exception {
return checkGenerateExistAndGet(selectionGenerator.get()).generateCaCert(
subject, caNotBefore, caNotAfter, keyPair);
}
}