Ali Zhang | cc6101e | 2021-07-08 14:16:52 -0700 | [diff] [blame] | 1 | // Copyright 2021 The Pigweed Authors |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 4 | // use this file except in compliance with the License. You may obtain a copy of |
| 5 | // the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | // License for the specific language governing permissions and limitations under |
| 13 | // the License. |
| 14 | |
| 15 | #include "mbedtls/ecdsa.h" |
| 16 | #include "pw_crypto/ecdsa.h" |
| 17 | #include "pw_function/function.h" |
| 18 | #include "pw_log/log.h" |
| 19 | |
| 20 | namespace pw::crypto::ecdsa { |
| 21 | |
| 22 | namespace { |
| 23 | |
| 24 | // Defer calls a given function upon exiting a scope. |
| 25 | class Defer { |
| 26 | public: |
| 27 | Defer(pw::Function<void(void)> callback) : callback_(std::move(callback)) {} |
| 28 | ~Defer() { callback_(); } |
| 29 | |
| 30 | private: |
| 31 | pw::Function<void(void)> callback_; |
| 32 | }; |
| 33 | |
| 34 | } // namespace |
| 35 | |
| 36 | constexpr size_t kP256CurveOrderBytes = 32; |
| 37 | |
| 38 | Status VerifyP256Signature(ConstByteSpan public_key, |
| 39 | ConstByteSpan digest, |
| 40 | ConstByteSpan signature) { |
| 41 | // Use a local structure to avoid going over the default inline storage |
| 42 | // for the `cleanup` callable used below. |
| 43 | struct { |
| 44 | // The elliptic curve group. |
| 45 | mbedtls_ecp_group grp; |
| 46 | // The public key point. |
| 47 | mbedtls_ecp_point Q; |
| 48 | // The signature (r, s). |
| 49 | mbedtls_mpi r, s; |
| 50 | } ctx; |
| 51 | |
| 52 | const uint8_t* public_key_data = |
| 53 | reinterpret_cast<const uint8_t*>(public_key.data()); |
| 54 | const uint8_t* digest_data = reinterpret_cast<const uint8_t*>(digest.data()); |
| 55 | const uint8_t* signature_data = |
| 56 | reinterpret_cast<const uint8_t*>(signature.data()); |
| 57 | |
| 58 | // These init functions never fail. |
| 59 | mbedtls_ecp_group_init(&ctx.grp); |
| 60 | mbedtls_ecp_point_init(&ctx.Q); |
| 61 | mbedtls_mpi_init(&ctx.r); |
| 62 | mbedtls_mpi_init(&ctx.s); |
| 63 | |
| 64 | // Auto clean up on exit. |
| 65 | Defer cleanup([&ctx](void) { |
| 66 | mbedtls_ecp_group_free(&ctx.grp); |
| 67 | mbedtls_ecp_point_free(&ctx.Q); |
| 68 | mbedtls_mpi_free(&ctx.r); |
| 69 | mbedtls_mpi_free(&ctx.s); |
| 70 | }); |
| 71 | |
| 72 | // Load the curve parameters. |
| 73 | if (mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1)) { |
| 74 | return Status::Internal(); |
| 75 | } |
| 76 | |
| 77 | // Load the public key. |
| 78 | if (mbedtls_ecp_point_read_binary( |
| 79 | &ctx.grp, &ctx.Q, public_key_data, public_key.size())) { |
| 80 | PW_LOG_ERROR("Bad public key format."); |
| 81 | return Status::InvalidArgument(); |
| 82 | } |
| 83 | |
| 84 | // Load the signature. |
| 85 | if (signature.size() != kP256CurveOrderBytes * 2) { |
| 86 | PW_LOG_ERROR("Bad signature format."); |
| 87 | return Status::InvalidArgument(); |
| 88 | } |
| 89 | |
| 90 | if (mbedtls_mpi_read_binary(&ctx.r, signature_data, kP256CurveOrderBytes) || |
| 91 | mbedtls_mpi_read_binary(&ctx.s, |
| 92 | signature_data + kP256CurveOrderBytes, |
| 93 | kP256CurveOrderBytes)) { |
| 94 | return Status::Internal(); |
| 95 | } |
| 96 | |
| 97 | // Digest must be 32 bytes or longer (and be truncated). |
| 98 | if (digest.size() < kP256CurveOrderBytes) { |
| 99 | return Status::InvalidArgument(); |
| 100 | } |
| 101 | |
| 102 | // Verify the signature. |
| 103 | if (mbedtls_ecdsa_verify( |
| 104 | &ctx.grp, digest_data, digest.size(), &ctx.Q, &ctx.r, &ctx.s)) { |
| 105 | PW_LOG_ERROR("Digital signature failed verification."); |
Ali Zhang | 5e619a2 | 2021-08-18 10:57:41 -0700 | [diff] [blame^] | 106 | return Status::Unauthenticated(); |
Ali Zhang | cc6101e | 2021-07-08 14:16:52 -0700 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | return OkStatus(); |
| 110 | } |
| 111 | |
| 112 | } // namespace pw::crypto::ecdsa |