Я предоставляю свое собственное решение проблемы:
Я основал свое решение на библиотеке BouncyCastle (для анализа частей токена) и JaasLounge (для расшифровки зашифрованной части токена).К сожалению, код для декодирования всего токена spnego из JaasLounge не удался для моих требований.Я должен был написать это сам.
Я декодировал билет по частям, сначала создавая DERObjects из массива byte []:
private DERObject[] readDERObjects(byte[] bytes) throws IOException {
ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(
bytes));
List<DERObject> objects = new ArrayList<DERObject>();
DERObject curObj;
while ((curObj = stream.readObject()) != null) {
objects.add(untag(curObj));
}
return objects.toArray(new DERObject[0]);
}
Untag () - моя вспомогательная функция, чтобыудалить обертку DERTaggedObject
private DERObject untag(DERObject src) {
if (src instanceof DERTaggedObject) {
return ((DERTaggedObject) src).getObject();
}
return src;
}
Для извлечения последовательности DERObject из заданного DERObject я написал еще одну вспомогательную функцию:
private DERObject[] readDERObjects(DERObject container) throws IOException {
// do operation varying from the type of container
if (container instanceof DERSequence) {
// decode using enumerator
List<DERObject> objects = new ArrayList<DERObject>();
DERSequence seq = (DERSequence) container;
Enumeration enumer = seq.getObjects();
while (enumer.hasMoreElements()) {
DERObject curObj = (DERObject) enumer.nextElement();
objects.add(untag(curObj));
}
return objects.toArray(new DERObject[0]);
}
if (container instanceof DERApplicationSpecific) {
DERApplicationSpecific aps = (DERApplicationSpecific) container;
byte[] bytes = aps.getContents();
return readDERObjects(bytes);
}
if (container instanceof DEROctetString) {
DEROctetString octets = (DEROctetString) container;
byte[] bytes = octets.getOctets();
return readDERObjects(bytes);
}
throw new IllegalArgumentException("Unable to decode sequence from "+container);
}
В конце, когда у меня появился DEROctetStream, он содержалзашифрованная часть, я только что использовал KerberosEncData:
KerberosEncData encData = new KerberosEncData(decrypted, matchingKey);
Последовательность байтов, которую мы получаем от браузера клиента, будет проанализирована в один DERApplicationSpecific, который является корневым уровнем билета 0.Корень содержит:
- DERObjectIdentifier - SPNEGO OID
- DERSequence - уровень 1
Уровень 1 содержит:
- SEQUENCE DERObjectIdentifier - типы мехов
- DEROctetString - завернутый DERApplicationSepecific - уровень 2
Уровень 2 содержит:
- DERObjectIndentifier - Kerberos OID
- KRB5_AP_REQ tag
0x01 0x00
, анализируется как логическое значение (false) - DERApplicationSpecific - контейнер DERSequence - уровень 3
Уровень 3 содержит:
- номер версии - должен быть 5
- тип сообщения - 14 (AP_REQ)
- опции AP (DERBITString)
- DERApplicationSpecific - завернутый DERSequence с частью билета
- DERSeqeuence с дополнительной частью билета - не обработано
Часть билета - уровень 4 содержит:
- Версия билета - должно быть 5
- Ticket realm - имя области, в которой аутентифицирован пользователь.
- DERSequence имен серверов.Каждому имени сервера соответствует DERSequence из двух строк: имя сервера и имя экземпляра
- DERSequence с зашифрованной частью
Последовательность зашифрованной части (уровень 5) содержит:
- Используемый номер алгоритма
- 1, 3 - DES
- 16 - des3-cbc-sha1-kd
- 17 - ETYPE-AES128-CTS-HMAC-SHA1-96
- 18 - ETYPE-AES256-CTS-HMAC-SHA1-96
- 23 - RC4-HMAC
- 24 - RC4-HMAC-EXP
- Номер версии ключа
- Зашифрованная часть (DEROctetStream)
Проблема была с конструктором DERBoolean, который выдает ArrayIndexOutOfBoundException, когда была найдена последовательность 0x01 0x00.Мне пришлось изменить этот конструктор:
public DERBoolean(
byte[] value)
{
// 2011-01-24 llech make it byte[0] proof, sequence 01 00 is KRB5_AP_REQ
if (value.length == 0)
this.value = 0;
else
this.value = value[0];
}