in kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java [110:267]
public boolean verify(KdcRequest kdcRequest, PluginRequestContext requestContext,
PaDataEntry paData) throws KrbException {
LOG.info("pkinit verify padata: entered!");
PkinitRequestContext reqCtx = (PkinitRequestContext) requestContext;
PrincipalName serverPrincipal = kdcRequest.getServerEntry().getPrincipal();
kdcRequest.setServerPrincipal(serverPrincipal);
PkinitKdcContext pkinitContext = findContext(serverPrincipal);
if (pkinitContext == null) {
return false;
}
reqCtx.paType = paData.getPaDataType();
if (paData.getPaDataType() == PaDataType.PK_AS_REQ) {
LOG.info("processing PK_AS_REQ");
PaPkAsReq paPkAsReq = KrbCodec.decode(paData.getPaDataValue(), PaPkAsReq.class);
byte[] signedAuthPack = paPkAsReq.getSignedAuthPack();
AuthPack authPack = null;
if (kdcRequest.isAnonymous()) {
EncapsulatedContentInfo eContentInfo = new EncapsulatedContentInfo();
try {
eContentInfo.decode(signedAuthPack);
} catch (IOException e) {
LOG.error("Fail to decode signedAuthPack. " + e);
}
authPack = KrbCodec.decode(eContentInfo.getContent(), AuthPack.class);
} else {
ContentInfo contentInfo = new ContentInfo();
try {
contentInfo.decode(signedAuthPack);
} catch (IOException e) {
LOG.error("Fail to decode signedAuthPack");
}
SignedData signedData = contentInfo.getContentAs(SignedData.class);
PkinitCrypto.verifyCmsSignedData(CmsMessageType.CMS_SIGN_CLIENT, signedData);
boolean isSigned = signedData.isSigned();
if (isSigned) {
//TODO
LOG.info("Signed data.");
} else {
PrincipalName clientPrincial = kdcRequest.getClientEntry().getPrincipal();
PrincipalName anonymousPrincipal = KrbUtil.makeAnonymousPrincipal();
/* If anonymous requests are being used, adjust the realm of the client principal. */
if (kdcRequest.getKdcOptions().isFlagSet(KdcOption.REQUEST_ANONYMOUS)
&& !KrbUtil.pricipalCompareIgnoreRealm(clientPrincial, anonymousPrincipal)) {
String errMsg = "Pkinit request not signed, but client not anonymous.";
LOG.error(errMsg);
throw new KrbException(KrbErrorCode.KDC_ERR_PREAUTH_FAILED, errMsg);
}
}
authPack = KrbCodec.decode(
signedData.getEncapContentInfo().getContent(), AuthPack.class);
}
PkAuthenticator pkAuthenticator = authPack.getPkAuthenticator();
checkClockskew(kdcRequest, pkAuthenticator.getCtime());
byte[] reqBodyBytes = null;
if (kdcRequest.getReqPackage() == null) {
LOG.error("ReqBodyBytes isn't available");
return false;
} else {
Asn1ParseResult parseResult = null;
try {
parseResult = Asn1.parse(kdcRequest.getReqPackage());
} catch (IOException e) {
LOG.error("Fail to parse reqPackage. " + e);
}
/**Get REQ_BODY in KDC_REQ for checksum*/
Asn1Container container = (Asn1Container) parseResult;
List<Asn1ParseResult> parseResults = container.getChildren();
Asn1Container parsingItem = (Asn1Container) parseResults.get(0);
List<Asn1ParseResult> items = parsingItem.getChildren();
if (items.size() > 3) {
ByteBuffer bodyBuffer = items.get(3).getBodyBuffer();
reqBodyBytes = new byte[bodyBuffer.remaining()];
bodyBuffer.get(reqBodyBytes);
}
}
CheckSum expectedCheckSum = null;
try {
expectedCheckSum = CheckSumUtil.makeCheckSum(CheckSumType.NIST_SHA,
reqBodyBytes);
} catch (KrbException e) {
LOG.error("Unable to calculate AS REQ checksum. {}", e.getMessage());
}
byte[] receivedCheckSumByte = pkAuthenticator.getPaChecksum();
if (expectedCheckSum.getChecksum().length != receivedCheckSumByte.length
|| !Arrays.equals(expectedCheckSum.getChecksum(), receivedCheckSumByte)) {
LOG.debug("received checksum length: " + receivedCheckSumByte.length
+ ", expected checksum type: " + expectedCheckSum.getCksumtype()
+ ", expected checksum length: " + expectedCheckSum.encodingLength());
String errorMessage = "Failed to match the checksum.";
LOG.error(errorMessage);
throw new KrbException(KrbErrorCode.KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED, errorMessage);
}
SubjectPublicKeyInfo publicKeyInfo = authPack.getClientPublicValue();
DhParameter dhParameter;
if (publicKeyInfo.getSubjectPubKey() != null) {
dhParameter = authPack.getClientPublicValue().getAlgorithm().getParametersAs(DhParameter.class);
PkinitCrypto.serverCheckDH(pkinitContext.pluginOpts, pkinitContext.cryptoctx, dhParameter);
byte[] clientSubjectPubKey = publicKeyInfo.getSubjectPubKey().getValue();
Asn1Integer clientPubKey = KrbCodec.decode(clientSubjectPubKey, Asn1Integer.class);
BigInteger y = clientPubKey.getValue();
BigInteger p = dhParameter.getP();
BigInteger g = dhParameter.getG();
DHPublicKey dhPublicKey = PkinitCrypto.createDHPublicKey(p, g, y);
DiffieHellmanServer server = new DiffieHellmanServer();
DHPublicKey serverPubKey = null;
try {
serverPubKey = (DHPublicKey) server.initAndDoPhase(dhPublicKey.getEncoded());
} catch (Exception e) {
LOG.error("Fail to create server public key.", e);
}
EncryptionKey secretKey = server.generateKey(null, null, kdcRequest.getEncryptionType());
// Set the DH shared key as the client key
kdcRequest.setClientKey(secretKey);
String identity = pkinitContext.identityOpts.getIdentity();
PaPkAsRep paPkAsRep = makePaPkAsRep(serverPubKey, identity);
PaDataEntry paDataEntry = makeEntry(paPkAsRep);
kdcRequest.getPreauthContext().getOutputPaData().add(paDataEntry);
} else {
if (!kdcRequest.isAnonymous()) {
/*Anonymous pkinit requires DH*/
String errMessage = "Anonymous pkinit without DH public value not supported.";
LOG.error(errMessage);
throw new KrbException(KrbErrorCode.KDC_ERR_PREAUTH_FAILED, errMessage);
} else {
// rsa
System.out.println("rsa");
}
}
}
return true;
}