private void processReply()

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);
            }
        }
    }