1 /*
2  * Copyright (C) 2023 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 package android.security.rkp.service;
18 
19 import static android.annotation.SystemApi.Client.SYSTEM_SERVER;
20 
21 import static java.lang.annotation.RetentionPolicy.SOURCE;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.SystemApi;
26 
27 import java.lang.annotation.Retention;
28 
29 /**
30  * Represents an error that occurred while calling into rkpd-hosted service(s).
31  * @hide
32  */
33 @SystemApi(client = SYSTEM_SERVER)
34 public final class RkpProxyException extends Exception {
35     /**
36      * An unexpected error occurred and there's no standard way to describe it. See the
37      * corresponding error string for more information.
38      */
39     public static final int ERROR_UNKNOWN = 0;
40 
41     /**
42      * Device will not receive remotely provisioned keys because it's running vulnerable
43      * code. The device needs to be updated to a fixed build to recover.
44      */
45     public static final int ERROR_REQUIRES_SECURITY_PATCH = 1;
46 
47     /**
48      * Indicates that the attestation key pool has been exhausted, and the remote key
49      * provisioning server cannot currently be reached. Clients should wait for the
50      * device to have connectivity, then retry.
51      */
52     public static final int ERROR_PENDING_INTERNET_CONNECTIVITY = 2;
53 
54     /**
55      * Indicates that this device will never be able to provision attestation keys using
56      * the remote provisioning server. This may be due to multiple causes, such as the
57      * device is not registered with the remote provisioning backend or the device has
58      * been permanently revoked. Clients who receive this error should not attempt to
59      * retry key creation.
60      */
61     public static final int ERROR_PERMANENT = 3;
62 
63     /** @hide */
64     @Retention(SOURCE)
65     @IntDef(prefix = {"ERROR_"},
66             value = {ERROR_UNKNOWN,
67                     ERROR_REQUIRES_SECURITY_PATCH,
68                     ERROR_PENDING_INTERNET_CONNECTIVITY,
69                     ERROR_PERMANENT})
70     public @interface ErrorCode {}
71 
72     @ErrorCode
73     private final int mError;
74 
75     /**
76      * @param error   the underlying ServerInterface error
77      * @param message describes the exception
78      */
RkpProxyException(@rrorCode int error, @NonNull String message)79     public RkpProxyException(@ErrorCode int error, @NonNull String message) {
80         super(message);
81         mError = error;
82     }
83 
84     /**
85      * @param error   the underlying ServerInterface error
86      * @param message describes the exception
87      * @param cause   the underlying error that led this exception
88      */
RkpProxyException(@rrorCode int error, @NonNull String message, @NonNull Throwable cause)89     public RkpProxyException(@ErrorCode int error, @NonNull String message,
90             @NonNull Throwable cause) {
91         super(message, cause);
92         mError = error;
93     }
94 
95     /**
96      * @return the underlying error that caused the failure
97      */
98     @ErrorCode
getError()99     public int getError() {
100         return mError;
101     }
102 
103     /**
104      * @return A human-readable string representation of the exception
105      */
106     @Override
107     @NonNull
getMessage()108     public String getMessage() {
109         return errorString() + ": " + super.getMessage();
110     }
111 
112     @NonNull
errorString()113     private String errorString() {
114         switch (mError) {
115             case ERROR_UNKNOWN:
116                 return "ERROR_UNKNOWN";
117             case ERROR_REQUIRES_SECURITY_PATCH:
118                 return "ERROR_REQUIRES_SECURITY_PATCH";
119             case ERROR_PENDING_INTERNET_CONNECTIVITY:
120                 return "ERROR_PENDING_INTERNET_CONNECTIVITY";
121             case ERROR_PERMANENT:
122                 return "ERROR_PERMANENT";
123             default:
124                 return "<Unknown error code " + mError + ">";
125         }
126     }
127 }
128