blob: 563a5b3a652169a9252aa524a5ccef4630d8a169 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.kerby.kerberos.kerb.request;
import org.apache.kerby.kerberos.kerb.KrbErrorCode;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
import org.apache.kerby.kerberos.kerb.type.KerberosTime;
import org.apache.kerby.kerberos.kerb.type.ap.ApOption;
import org.apache.kerby.kerberos.kerb.type.ap.ApOptions;
import org.apache.kerby.kerberos.kerb.type.ap.ApReq;
import org.apache.kerby.kerberos.kerb.type.ap.Authenticator;
import org.apache.kerby.kerberos.kerb.type.base.EncryptedData;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.HostAddresses;
import org.apache.kerby.kerberos.kerb.type.base.KeyUsage;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
import java.net.InetAddress;
import java.util.EnumSet;
/**
* A wrapper for ApReq request
* The client principal and sgt ticket are needed to create ApReq message.
*/
public class ApRequest {
private PrincipalName clientPrincipal;
private SgtTicket sgtTicket;
private ApReq apReq;
private EnumSet<ApOption> flags;
public ApRequest(PrincipalName clientPrincipal, SgtTicket sgtTicket) {
this(clientPrincipal, sgtTicket, EnumSet.of(ApOption.USE_SESSION_KEY));
}
public ApRequest(PrincipalName clientPrincipal, SgtTicket sgtTicket, EnumSet<ApOption> flags) {
this.clientPrincipal = clientPrincipal;
this.sgtTicket = sgtTicket;
this.flags = flags;
}
public ApReq getApReq() throws KrbException {
if (apReq == null) {
apReq = makeApReq();
}
return apReq;
}
public void setApReq(ApReq apReq) {
this.apReq = apReq;
}
private ApReq makeApReq() throws KrbException {
ApReq apReq = new ApReq();
Authenticator authenticator = makeAuthenticator();
EncryptionKey sessionKey = sgtTicket.getSessionKey();
EncryptedData authData = EncryptionUtil.seal(authenticator,
sessionKey, KeyUsage.AP_REQ_AUTH);
apReq.setEncryptedAuthenticator(authData);
apReq.setAuthenticator(authenticator);
apReq.setTicket(sgtTicket.getTicket());
ApOptions apOptions = new ApOptions();
for (ApOption flag : flags) {
apOptions.setFlag(flag);
}
apReq.setApOptions(apOptions);
return apReq;
}
/*
* Make the Authenticator for ApReq.
*/
private Authenticator makeAuthenticator() throws KrbException {
Authenticator authenticator = new Authenticator();
authenticator.setAuthenticatorVno(5);
authenticator.setCname(clientPrincipal);
authenticator.setCrealm(sgtTicket.getRealm());
long millis = System.currentTimeMillis();
int usec = (int) (millis % 1000) * 1000;
millis -= millis % 1000;
authenticator.setCtime(new KerberosTime(millis));
authenticator.setCusec(usec);
if (flags.contains(ApOption.USE_SESSION_KEY)) {
authenticator.setSubKey(sgtTicket.getSessionKey());
}
return authenticator;
}
/*
* Validate the ApReq.
*/
public static void validate(EncryptionKey encKey, ApReq apReq) throws KrbException {
Ticket ticket = apReq.getTicket();
if (encKey == null) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_NOKEY);
}
EncTicketPart encPart = EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
encKey, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
ticket.setEncPart(encPart);
unsealAuthenticator(encPart.getKey(), apReq);
Authenticator authenticator = apReq.getAuthenticator();
if (!authenticator.getCname().equals(ticket.getEncPart().getCname())) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADMATCH);
}
if (!authenticator.getCrealm().equals(ticket.getEncPart().getCrealm())) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADMATCH);
}
}
/*
* Validate the ApReq with channel binding and time
*/
public static void validate(EncryptionKey encKey, ApReq apReq,
InetAddress initiator,
long timeSkew) throws KrbException {
validate(encKey, apReq);
Ticket ticket = apReq.getTicket();
EncTicketPart tktEncPart = ticket.getEncPart();
Authenticator authenticator = apReq.getAuthenticator();
if (initiator != null) {
HostAddresses clientAddrs = tktEncPart.getClientAddresses();
if (clientAddrs != null && !clientAddrs.contains(initiator)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
}
}
if (timeSkew != 0) {
if (!authenticator.getCtime().isInClockSkew(timeSkew)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_SKEW);
}
KerberosTime now = KerberosTime.now();
KerberosTime startTime = tktEncPart.getStartTime();
if (startTime != null && !startTime.lessThanWithSkew(now, timeSkew)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_NYV);
}
if (tktEncPart.getEndTime().lessThanWithSkew(now, timeSkew)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_EXPIRED);
}
}
}
/*
* Unseal the authenticator through the encryption key from ticket
*/
public static void unsealAuthenticator(EncryptionKey encKey, ApReq apReq) throws KrbException {
EncryptedData authData = apReq.getEncryptedAuthenticator();
Authenticator authenticator = EncryptionUtil.unseal(authData,
encKey, KeyUsage.AP_REQ_AUTH, Authenticator.class);
apReq.setAuthenticator(authenticator);
}
}