absl::StatusOr CreateKeyAndVersion()

in kmsp11/session.cc [193:252]


absl::StatusOr<CryptoKeyAndVersion> CreateKeyAndVersion(
    const KmsClient& client, std::string_view key_ring_name,
    const KeyGenerationParams& gen_params,
    bool experimental_create_multiple_versions, bool allow_software_keys) {
  if (experimental_create_multiple_versions) {
    kms_v1::GetCryptoKeyRequest req;
    req.set_name(absl::StrCat(key_ring_name, "/cryptoKeys/", gen_params.label));
    absl::StatusOr<kms_v1::CryptoKey> ck = client.GetCryptoKey(req);
    switch (ck.status().code()) {
      case absl::StatusCode::kOk: {
        ASSIGN_OR_RETURN(kms_v1::CryptoKeyVersion ckv,
                         CreateNewVersionOfExistingKey(client, *ck, gen_params,
                                                       allow_software_keys));
        return CryptoKeyAndVersion{*ck, ckv};
      }
      case absl::StatusCode::kNotFound:
        // The CryptoKey doesn't exist; continue on to create it.
        break;
      default:
        return ck.status();
    }
  }

  kms_v1::CreateCryptoKeyRequest req;
  req.set_parent(std::string(key_ring_name));
  req.set_crypto_key_id(gen_params.label);
  req.mutable_crypto_key()->set_purpose(gen_params.algorithm.purpose);
  req.mutable_crypto_key()->mutable_version_template()->set_algorithm(
      gen_params.algorithm.algorithm);
  // Unless otherwise specified in the key generation params, we generate keys
  // with protection level = HSM.
  if (gen_params.protection_level.has_value()) {
    req.mutable_crypto_key()->mutable_version_template()->set_protection_level(
        *gen_params.protection_level);
  } else {
    req.mutable_crypto_key()->mutable_version_template()->set_protection_level(
        kms_v1::HSM);
  }

  absl::StatusOr<CryptoKeyAndVersion> key_and_version =
      client.CreateCryptoKeyAndWaitForFirstVersion(req);
  if (absl::IsAlreadyExists(key_and_version.status())) {
    if (experimental_create_multiple_versions) {
      // If we choose to make this experiment a full-fledged feature, we should
      // gracefully handle the case where the CryptoKey is created by another
      // (thread|process|caller) while this request is in flight.
      //
      // That recursive logic will be sort of ugly and complicated; just
      // returning CKR_DEVICE_ERROR/AlreadyExists here seems fine for the
      // purposes of the experiment.
      return key_and_version.status();
    }
    return NewError(
        absl::StatusCode::kAlreadyExists,
        absl::StrFormat("key with label %s already exists: %s",
                        gen_params.label, key_and_version.status().message()),
        CKR_ARGUMENTS_BAD, SOURCE_LOCATION);
  }
  return key_and_version;
}