1 /*
2 * Copyright 2024 Michael Osipov
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.michaelo.tomcat.pac.asn1;
17
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Objects;
22
23 import org.apache.tomcat.util.buf.Asn1Parser;
24
25 import com.sun.security.jgss.AuthorizationDataEntry;
26
27 /**
28 * A minimalist ASN.1 parser for Kerberos {@code AuthorizationData} according to RFC 4120, section
29 * 5.2.6 for the {@code AD-IF-RELEVANT} type. It unwraps all nested data as described in <a href=
30 * "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/21181737-74fd-492c-bfbd-0322993a9061">MS-PAC
31 * structure</a>.
32 */
33 public class AdIfRelevantAsn1Parser {
34
35 /*
36 * AD types as per: https://github.com/krb5/krb5-assignments/blob/master/ad-type
37 */
38 public static final int AD_IF_RELEVANT = 1;
39 public static final int AD_WIN2K_PAC = 128;
40
41 private AdIfRelevantAsn1Parser() {
42 }
43
44 /**
45 * Parses the ASN.1 structure and converts to a list of {@code AuthorizationDataEntry} elements.
46 *
47 * @param adIfRelevant
48 * ASN.1 encoded data
49 * @return a list of {@code AuthorizationDataEntry} elements
50 * @throws NullPointerException
51 * if {@code adIfRelevant} is null
52 * @throws IllegalArgumentException
53 * if {@code adIfRelevant} is empty
54 */
55 public static List<AuthorizationDataEntry> parse(byte[] adIfRelevant) {
56 Objects.requireNonNull(adIfRelevant, "adIfRelevant cannot be null");
57 if (adIfRelevant.length == 0)
58 throw new IllegalArgumentException("adIfRelevant cannot be empty");
59
60 List<AuthorizationDataEntry> adEntries = new ArrayList<>();
61
62 Asn1Parser parser = new Asn1Parser(adIfRelevant);
63 parser.parseTagSequence();
64 parser.parseFullLength();
65 while (!parser.eof()) {
66 parser.parseTagSequence();
67 parser.parseLength();
68 Asn1Parser p = new Asn1Parser(parser.parseAttributeAsBytes(0));
69 BigInteger type = p.parseInt();
70 p = new Asn1Parser(parser.parseAttributeAsBytes(1));
71 byte[] data = p.parseOctetString();
72 adEntries.add(new AuthorizationDataEntry(type.intValue(), data));
73 }
74
75 return adEntries;
76 }
77
78 }