View Javadoc
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  }