// Copyright 2023 Google LLC
//
// 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
//
//     https://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 <stdint.h>
#include <string.h>

#include "cose/cose.h"
#include "cose/cose_configure.h"
#include "cose_int.h"
#include "openssl/bn.h"
#include "openssl/ec.h"
#include "openssl/ec_key.h"
#include "openssl/ecdsa.h"
#include "openssl/evp.h"
#include "openssl/hkdf.h"
#include "openssl/is_boringssl.h"
#include "openssl/sha.h"

// Gets the public key from a well-formed ECDSA P-384 COSE_Key. On
// success populates |public_key| and returns true; public_key must hold 96
// bytes (uncompressed format).
static bool GetPublicKeyFromCbor(const cn_cbor *key, uint8_t *public_key) {
  const int64_t kCoseKeyAlgLabel = 3;
  const int64_t kCoseKeyOpsLabel = 4;
  const uint64_t kCoseKeyOpsVerify = 2;
  const int64_t kCoseAlgEs384 = -35;

  // Mandatory attributes.
  cn_cbor *type = cn_cbor_mapget_int(key, COSE_Key_Type);
  cn_cbor *curve = cn_cbor_mapget_int(key, COSE_Key_OPK_Curve);
  if (!type || !curve) {
    return false;
  }
  if (type->type != CN_CBOR_UINT || curve->type != CN_CBOR_UINT) {
    return false;
  }

  if (type->v.uint != COSE_Key_Type_EC2 || curve->v.uint != COSE_Curve_P384) {
    return false;
  }

  cn_cbor *x = cn_cbor_mapget_int(key, COSE_Key_EC2_X);
  if (!x || x->type != CN_CBOR_BYTES || x->length != (PUBLIC_KEY_SIZE / 2)) {
    return false;
  }

  cn_cbor *y = cn_cbor_mapget_int(key, COSE_Key_EC2_Y);
  if (!y || y->type != CN_CBOR_BYTES || y->length != (PUBLIC_KEY_SIZE / 2)) {
    return false;
  }

  cn_cbor *alg = cn_cbor_mapget_int(key, kCoseKeyAlgLabel);
  if (alg) {
    if (alg->type != CN_CBOR_INT || alg->v.sint != kCoseAlgEs384) {
      return false;
    }
  }

  cn_cbor *ops = cn_cbor_mapget_int(key, kCoseKeyOpsLabel);
  if (ops) {
    if (ops->type != CN_CBOR_ARRAY || ops->length == 0) {
      return false;
    }
    bool found_verify = false;
    for (size_t i = 0; i < ops->length; ++i) {
      cn_cbor *item = cn_cbor_index(ops, i);
      if (!item || item->type != CN_CBOR_UINT) {
        return false;
      }
      if (item->v.uint == kCoseKeyOpsVerify) {
        found_verify = true;
      }
    }
    if (!found_verify) {
      return false;
    }
  }

  memcpy(&public_key[0], x->v.bytes, PUBLIC_KEY_SIZE / 2);
  memcpy(&public_key[PUBLIC_KEY_SIZE / 2], y->v.bytes, PUBLIC_KEY_SIZE / 2);
  return true;
}

// A simple implementation of 'ECDSA_Verify' using boringssl. This function is
// required by 'COSE_Sign1_validate'.
bool ECDSA_Verify(COSE *cose_signer, int signature_index, COSE_KEY *cose_key,
                  int cbitsDigest, const byte *message, size_t message_size,
                  cose_errback *) {
  (void)cbitsDigest;
  cn_cbor *signature = _COSE_arrayget_int(cose_signer, signature_index);
  cn_cbor *key = cose_key->m_cborKey;
  if (!signature || !key) {
    return false;
  }
  if (signature->type != CN_CBOR_BYTES ||
      signature->length != PUBLIC_KEY_SIZE) {
    return false;
  }
  uint8_t public_key[PUBLIC_KEY_SIZE];
  if (!GetPublicKeyFromCbor(key, public_key)) {
    return false;
  }

  // Implementation of ECDSA verification starts here
  uint8_t output[48];
  SHA384(message, message_size, output);
  EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
  BIGNUM *x = BN_new();
  BN_bin2bn(&public_key[0], 48, x);
  BIGNUM *y = BN_new();
  BN_bin2bn(&public_key[48], 48, y);
  int result = EC_KEY_set_public_key_affine_coordinates(eckey, x, y);

  BN_clear_free(y);
  BN_clear_free(x);

  if (result == 0) {
    printf("Setting affine coordinates failed\n");
    return false;
  }

  ECDSA_SIG *sig = ECDSA_SIG_new();
  BN_bin2bn(&(signature->v.bytes[0]), 48, sig->r);
  BN_bin2bn(&(signature->v.bytes[48]), 48, sig->s);
  result = ECDSA_do_verify(output, 48, sig, eckey);

  EC_KEY_free(eckey);
  ECDSA_SIG_free(sig);
  if (1 != result) {
    return false;
  }
  return true;
}

// A stub for 'ECDSA_Sign'. This is unused, but helps make linkers happy.
bool ECDSA_Sign(COSE * /*cose_signer*/, int /*signature_index*/,
                COSE_KEY * /*cose_key*/, const byte * /*message*/,
                size_t /*message_size*/, cose_errback *) {
  return false;
}
