• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.adservices.service.adselection.signature;
18 
19 import android.annotation.NonNull;
20 
21 import com.android.adservices.LoggerFactory;
22 import com.android.adservices.service.stats.SignatureVerificationLogger;
23 
24 import com.google.common.annotations.VisibleForTesting;
25 
26 import java.security.InvalidKeyException;
27 import java.security.KeyFactory;
28 import java.security.PublicKey;
29 import java.security.Signature;
30 import java.security.SignatureException;
31 import java.security.spec.InvalidKeySpecException;
32 import java.security.spec.X509EncodedKeySpec;
33 import java.util.Objects;
34 
35 /** Verifies signatures using ECDSA algorithm (aka. ECDSAwithSHA256). */
36 public class ECDSASignatureVerifier implements SignatureVerifier {
37     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
38 
39     @VisibleForTesting
40     protected static final String UNKNOWN_ERROR =
41             "An unknown error occurred during signature verification";
42 
43     @VisibleForTesting
44     protected static final String INVALID_KEY_ERROR =
45             "Given key is either null or not suitable with the specified algorithm: ECDSA";
46 
47     @VisibleForTesting
48     protected static final String SIGNATURE_VALIDATION_ERROR =
49             "Encounter error during signature verification";
50 
51     @VisibleForTesting protected static final String EC_KEY_ALGORITHM = "EC";
52 
53     @VisibleForTesting
54     protected static final String ECDSA_WITH_SHA256_SIGNING_ALGORITHM = "SHA256withECDSA";
55 
56     @NonNull private final SignatureVerificationLogger mSignatureVerificationLogger;
57 
ECDSASignatureVerifier( @onNull SignatureVerificationLogger signatureVerificationLogger)58     public ECDSASignatureVerifier(
59             @NonNull SignatureVerificationLogger signatureVerificationLogger) {
60         Objects.requireNonNull(signatureVerificationLogger);
61 
62         mSignatureVerificationLogger = signatureVerificationLogger;
63     }
64 
65     /**
66      * Verifies a given signature against the given public key and the serialized data.
67      *
68      * <p>Verifies the signature created by ECDSAwithSHA256 algorithm
69      *
70      * @param publicKey public key paired with the private key used to sign the data
71      * @param data serialized representation of the data
72      * @param signature signature to verify
73      */
74     @Override
verify(byte[] publicKey, byte[] data, byte[] signature)75     public boolean verify(byte[] publicKey, byte[] data, byte[] signature) {
76         try {
77             KeyFactory keyFactory = KeyFactory.getInstance(EC_KEY_ALGORITHM);
78             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
79             PublicKey aPublicKey = keyFactory.generatePublic(keySpec);
80             // TODO(b/311368820): Make this singleton to avoid initializing it every time
81             Signature ecdsa = Signature.getInstance(ECDSA_WITH_SHA256_SIGNING_ALGORITHM);
82             ecdsa.initVerify(aPublicKey);
83             ecdsa.update(data);
84             return ecdsa.verify(signature);
85         } catch (InvalidKeySpecException | InvalidKeyException | NullPointerException error) {
86             sLogger.e(error, INVALID_KEY_ERROR);
87             logWrongKeyFormatError();
88             return false;
89         } catch (SignatureException error) {
90             sLogger.e(error, SIGNATURE_VALIDATION_ERROR);
91             logSignatureFormatError();
92             return false;
93         } catch (Exception error) {
94             sLogger.e(error, UNKNOWN_ERROR);
95             logUnknownError();
96             return false;
97         }
98     }
99 
logWrongKeyFormatError()100     private void logWrongKeyFormatError() {
101         mSignatureVerificationLogger.addFailureDetailCountOfKeysWithWrongFormat();
102     }
103 
logSignatureFormatError()104     private void logSignatureFormatError() {
105         mSignatureVerificationLogger.setFailureDetailWrongSignatureFormat();
106     }
107 
logUnknownError()108     private void logUnknownError() {
109         mSignatureVerificationLogger.setFailureDetailUnknownError();
110     }
111 }
112