1 /*
2  * Copyright (C) 2017 The Android Open Source Project
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 /*
17  * Copyright (c) 2017, The Linux Foundation.
18  */
19 
20 /*
21  * Copyright 2012 Giesecke & Devrient GmbH.
22  *
23  * Licensed under the Apache License, Version 2.0 (the "License");
24  * you may not use this file except in compliance with the License.
25  * You may obtain a copy of the License at
26  *
27  *      http://www.apache.org/licenses/LICENSE-2.0
28  *
29  * Unless required by applicable law or agreed to in writing, software
30  * distributed under the License is distributed on an "AS IS" BASIS,
31  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32  * See the License for the specific language governing permissions and
33  * limitations under the License.
34  */
35 package com.android.se.security.gpac;
36 
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 
40 /**
41  * This class represents the Access rule data object (AR-DO), according to GP Secure Element Control
42  * Access.
43  *
44  * <p>The AR-DO contains one or two access rules of type APDU or NFC.
45  */
46 public class AR_DO extends BerTlv {
47 
48     public static final int TAG = 0xE3;
49 
50     private APDU_AR_DO mApduAr = null;
51     private NFC_AR_DO mNfcAr = null;
52     private PERM_AR_DO mPermAr = null;
53 
AR_DO(byte[] rawData, int valueIndex, int valueLength)54     public AR_DO(byte[] rawData, int valueIndex, int valueLength) {
55         super(rawData, TAG, valueIndex, valueLength);
56     }
57 
AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo, PERM_AR_DO permArDo)58     public AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo, PERM_AR_DO permArDo) {
59         super(null, TAG, 0, 0);
60         mApduAr = apduArDo;
61         mNfcAr = nfcArDo;
62         mPermAr = permArDo;
63     }
64 
AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo)65     public AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo) {
66         super(null, TAG, 0, 0);
67         mApduAr = apduArDo;
68         mNfcAr = nfcArDo;
69         mPermAr = null;
70     }
71 
AR_DO(PERM_AR_DO permArDo)72     public AR_DO(PERM_AR_DO permArDo) {
73         super(null, TAG, 0, 0);
74         mApduAr = null;
75         mNfcAr = null;
76         mPermAr = permArDo;
77     }
78 
getApduArDo()79     public APDU_AR_DO getApduArDo() {
80         return mApduAr;
81     }
82 
getNfcArDo()83     public NFC_AR_DO getNfcArDo() {
84         return mNfcAr;
85     }
86 
getPermArDo()87     public PERM_AR_DO getPermArDo() {
88         return mPermAr;
89     }
90 
91     @Override
92     /**
93      * Interpret value.
94      *
95      * <p>Tag: E3
96      *
97      * <p>Value:
98      *     1. Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A
99      *        concatenation of one or two AR-DO(s). If two AR-DO(s) are present these must have
100      *        different types.
101      *     2. PERM-AR-DO
102      */
interpret()103     public void interpret() throws ParserException {
104 
105         this.mApduAr = null;
106         this.mNfcAr = null;
107         this.mPermAr = null;
108 
109         byte[] data = getRawData();
110         int index = getValueIndex();
111 
112         if (index + getValueLength() > data.length) {
113             throw new ParserException("Not enough data for AR_DO!");
114         }
115 
116         do {
117             BerTlv temp = BerTlv.decode(data, index);
118 
119             if (temp.getTag() == APDU_AR_DO.TAG) { // APDU-AR-DO
120                 mApduAr = new APDU_AR_DO(data, temp.getValueIndex(), temp.getValueLength());
121                 mApduAr.interpret();
122             } else if (temp.getTag() == NFC_AR_DO.TAG) { // NFC-AR-DO
123                 mNfcAr = new NFC_AR_DO(data, temp.getValueIndex(), temp.getValueLength());
124                 mNfcAr.interpret();
125             } else if (temp.getTag() == PERM_AR_DO.TAG) { // PERM-AR-DO
126                 mPermAr = new PERM_AR_DO(data, temp.getValueIndex(), temp.getValueLength());
127                 mPermAr.interpret();
128             } else {
129                 // un-comment following line if a more restrictive
130                 // behavior is necessary.
131                 // throw new ParserException("Invalid DO in AR-DO!");
132             }
133             index = temp.getValueIndex() + temp.getValueLength();
134         } while (getValueIndex() + getValueLength() > index);
135 
136         if (mApduAr == null && mNfcAr == null && mPermAr == null) {
137             throw new ParserException("No valid DO in AR-DO!");
138         }
139     }
140 
141     @Override
142     /**
143      * Interpret value.
144      *
145      * <p>Tag: E3
146      *
147      * <p>Value:
148      *     1. Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A
149      *        concatenation of one or two AR-DO(s). If two AR-DO(s) are present these must have
150      *        different types.
151      *     2. PERM-AR-DO
152      */
build(ByteArrayOutputStream stream)153     public void build(ByteArrayOutputStream stream) throws DO_Exception {
154 
155         // write tag
156         stream.write(getTag());
157 
158         ByteArrayOutputStream temp = new ByteArrayOutputStream();
159         if (mApduAr != null) {
160             mApduAr.build(temp);
161         }
162 
163         if (mNfcAr != null) {
164             mNfcAr.build(temp);
165         }
166 
167         if (mPermAr != null) {
168             mPermAr.build(temp);
169         }
170 
171         BerTlv.encodeLength(temp.size(), stream);
172         try {
173             stream.write(temp.toByteArray());
174         } catch (IOException e) {
175             throw new DO_Exception("AR-DO Memory IO problem! " + e.getMessage());
176         }
177     }
178 }
179