in kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/pkinit/PkinitPreauth.java [323:434]
private void processReply(KdcRequest kdcRequest,
PkinitRequestContext reqCtx,
PaDataEntry paEntry,
EncryptionType encType) throws KrbException {
// Parse PA-PK-AS-REP message.
if (paEntry.getPaDataType() == PaDataType.PK_AS_REP) {
LOG.info("processing PK_AS_REP");
PaPkAsRep paPkAsRep = KrbCodec.decode(paEntry.getPaDataValue(), PaPkAsRep.class);
DhRepInfo dhRepInfo = paPkAsRep.getDHRepInfo();
byte[] dhSignedData = dhRepInfo.getDHSignedData();
ContentInfo contentInfo = new ContentInfo();
try {
contentInfo.decode(dhSignedData);
} catch (IOException e) {
LOG.error("Fail to decode dhSignedData. " + e);
}
SignedData signedData = contentInfo.getContentAs(SignedData.class);
PkinitCrypto.verifyCmsSignedData(
CmsMessageType.CMS_SIGN_SERVER, signedData);
if (kdcRequest.getContext().getConfig().getPkinitAnchors().isEmpty()) {
LOG.error("No PKINIT anchors specified");
throw new KrbException("No PKINIT anchors specified");
}
String anchorFileName = kdcRequest.getContext().getConfig().getPkinitAnchors().get(0);
X509Certificate x509Certificate = null;
try {
List<java.security.cert.Certificate> certs =
CertificateHelper.loadCerts(anchorFileName);
if (certs != null && !certs.isEmpty()) {
x509Certificate = (X509Certificate) certs.iterator().next();
}
} catch (KrbException e) {
LOG.error("Fail to load certs from archor file. " + e);
}
if (x509Certificate == null) {
LOG.error("Failed to load PKINIT anchor");
throw new KrbException("Failed to load PKINIT anchor");
}
CertificateSet certificateSet = signedData.getCertificates();
if (certificateSet == null || certificateSet.getElements().isEmpty()) {
throw new KrbException("No PKINIT Certs");
}
List<Certificate> certificates = new ArrayList<>();
List<CertificateChoices> certificateChoicesList = certificateSet.getElements();
for (CertificateChoices certificateChoices : certificateChoicesList) {
certificates.add(certificateChoices.getCertificate());
}
try {
PkinitCrypto.validateChain(certificates, x509Certificate);
} catch (Exception e) {
throw new KrbException(KrbErrorCode.KDC_ERR_INVALID_CERTIFICATE, e);
}
PrincipalName kdcPrincipal = KrbUtil.makeTgsPrincipal(
kdcRequest.getContext().getConfig().getKdcRealm());
//TODO USE CertificateSet
boolean validSan = PkinitCrypto.verifyKdcSan(
kdcRequest.getContext().getConfig().getPkinitKdcHostName(), kdcPrincipal,
certificates);
if (!validSan) {
LOG.error("Did not find an acceptable SAN in KDC certificate");
}
LOG.info("skipping EKU check");
LOG.info("as_rep: DH key transport algorithm");
KdcDhKeyInfo kdcDhKeyInfo = new KdcDhKeyInfo();
try {
kdcDhKeyInfo.decode(signedData.getEncapContentInfo().getContent());
} catch (IOException e) {
String errMessage = "failed to decode KdcDhKeyInfo " + e.getMessage();
LOG.error(errMessage);
throw new KrbException(errMessage);
}
byte[] subjectPublicKey = kdcDhKeyInfo.getSubjectPublicKey().getValue();
Asn1Integer clientPubKey = KrbCodec.decode(subjectPublicKey, Asn1Integer.class);
BigInteger y = clientPubKey.getValue();
DiffieHellmanClient client = reqCtx.getDhClient();
BigInteger p = client.getDhParam().getP();
BigInteger g = client.getDhParam().getG();
DHPublicKey dhPublicKey = PkinitCrypto.createDHPublicKey(p, g, y);
EncryptionKey secretKey = null;
try {
client.doPhase(dhPublicKey.getEncoded());
secretKey = client.generateKey(null, null, encType);
} catch (Exception e) {
LOG.error("DiffieHellmanClient do parse failed. " + e);
}
// Set the DH shared key as the client key
if (secretKey == null) {
throw new KrbException("Fail to create client key.");
} else {
kdcRequest.setAsKey(secretKey);
}
}
}