summaryrefslogtreecommitdiffstats
path: root/legacy_support/ecdsa_keymaster1_operation.cpp
blob: e3d2ace3c98d4c62261b019c7976d3331dcd3d04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ecdsa_keymaster1_operation.h"

#include <memory>

#include <keymaster/android_keymaster_utils.h>
#include <keymaster/km_openssl/openssl_err.h>
#include <keymaster/km_openssl/openssl_utils.h>
#include <keymaster/legacy_support/ec_keymaster1_key.h>

using std::unique_ptr;

namespace keymaster {

keymaster_error_t EcdsaKeymaster1WrappedOperation::Begin(EVP_PKEY* ecdsa_key,
                                                         const AuthorizationSet& input_params) {
    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
    if (!key_data)
        return KM_ERROR_UNKNOWN_ERROR;

    // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified.  Also change
    // KM_PAD_ECDSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll
    // pass
    // to the hardware module.  The regular Ecdsa*Operation classes will do software digesting and
    // padding where we've told the HW not to.
    //
    // The reason we don't change KM_PAD_ECDSA_PKCS1_1_5_SIGN or KM_PAD_ECDSA_PKCS1_1_5_ENCRYPT to
    // KM_PAD_NONE is because the hardware can to those padding modes, since they don't involve
    // digesting.
    //
    // We also cache in the key the padding value that we expect to be passed to the engine crypto
    // operation.  This just allows us to double-check that the correct padding value is reaching
    // that layer.
    AuthorizationSet begin_params(input_params);
    int pos = begin_params.find(TAG_DIGEST);
    if (pos == -1)
        return KM_ERROR_UNSUPPORTED_DIGEST;
    begin_params[pos].enumerated = KM_DIGEST_NONE;

    return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material,
                                    &begin_params, nullptr /* out_params */, &operation_handle_);
}

keymaster_error_t
EcdsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* ecdsa_key,
                                               const AuthorizationSet& input_params) {
    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
    if (!key_data) {
        LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0);
        return KM_ERROR_UNKNOWN_ERROR;
    }
    key_data->op_handle = operation_handle_;
    key_data->finish_params.Reinitialize(input_params);

    return KM_ERROR_OK;
}

keymaster_error_t EcdsaKeymaster1WrappedOperation::Abort() {
    return engine_->device()->abort(engine_->device(), operation_handle_);
}

keymaster_error_t EcdsaKeymaster1WrappedOperation::GetError(EVP_PKEY* ecdsa_key) {
    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
    if (!key_data)
        return KM_ERROR_UNKNOWN_ERROR;
    return key_data->error;
}

static EVP_PKEY* GetEvpKey(const EcdsaKeymaster1Key& key, keymaster_error_t* error) {
    if (!key.key()) {
        *error = KM_ERROR_UNKNOWN_ERROR;
        return nullptr;
    }

    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
    if (!key.InternalToEvp(pkey.get())) {
        *error = KM_ERROR_UNKNOWN_ERROR;
        return nullptr;
    }
    return pkey.release();
}

OperationPtr EcdsaKeymaster1OperationFactory::CreateOperation(Key&& key,
                                                              const AuthorizationSet& begin_params,
                                                              keymaster_error_t* error) {
    keymaster_digest_t digest;
    if (!GetAndValidateDigest(begin_params, key, &digest, error)) return nullptr;

    const EcdsaKeymaster1Key& ecdsa_km1_key = static_cast<EcdsaKeymaster1Key&>(key);
    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> ecdsa(GetEvpKey(ecdsa_km1_key, error));
    if (!ecdsa) return nullptr;

    switch (purpose_) {
    case KM_PURPOSE_SIGN:
        return OperationPtr(new EcdsaKeymaster1Operation<EcdsaSignOperation>(
            key.hw_enforced_move(), key.sw_enforced_move(), digest, ecdsa.release(), engine_));
    default:
        LOG_E(
            "Bug: Pubkey operation requested.  Those should be handled by normal ECDSA operations.",
            0);
        *error = KM_ERROR_UNSUPPORTED_PURPOSE;
        return nullptr;
    }
}

static const keymaster_digest_t supported_digests[] = {
    KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
    KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};

const keymaster_digest_t*
EcdsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const {
    *digest_count = array_length(supported_digests);
    return supported_digests;
}

const keymaster_padding_t*
EcdsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
    *padding_mode_count = 0;
    return nullptr;
}

}  // namespace keymaster