blob: 554c9d37f0a8776525bfac39219fda78b16cb79e [file] [log] [blame]
// Copyright 2022 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
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.monitoring;
import com.google.crypto.tink.KeyStatus;
import com.google.crypto.tink.Parameters;
import com.google.crypto.tink.annotations.Alpha;
import com.google.errorprone.annotations.Immutable;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* Immutable representation of a Keyset in a certain point in time for the purpose of monitoring
* operations involving cryptographic keys.
*
* <p>Do not use. This API is not yet ready and may change or be removed.
*/
@Immutable
@Alpha
public final class MonitoringKeysetInfo {
/** Description about each entry of the Keyset. */
@Immutable
public static final class Entry {
private final KeyStatus status;
private final int keyId;
private final Parameters parameters;
public KeyStatus getStatus() {
return status;
}
public int getKeyId() {
return keyId;
}
public Parameters getParameters() {
return parameters;
}
private Entry(KeyStatus status, int keyId, Parameters parameters) {
this.status = status;
this.keyId = keyId;
this.parameters = parameters;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Entry)) {
return false;
}
Entry entry = (Entry) obj;
return this.status == entry.status
&& this.keyId == entry.keyId
&& this.parameters.equals(entry.parameters);
}
@Override
public int hashCode() {
return Objects.hash(status, keyId, parameters.hashCode());
}
@Override
public String toString() {
return String.format(
"(status=%s, keyId=%s, parameters='%s')", this.status, this.keyId, this.parameters);
}
}
/** Builder */
public static final class Builder {
// builderEntries == null indicates that build has already been called and the builder is not
// usable anymore.
@Nullable private ArrayList<Entry> builderEntries = new ArrayList<>();
private MonitoringAnnotations builderAnnotations = MonitoringAnnotations.EMPTY;
@Nullable private Integer builderPrimaryKeyId = null;
public Builder setAnnotations(MonitoringAnnotations annotations) {
if (builderEntries == null) {
throw new IllegalStateException("setAnnotations cannot be called after build()");
}
builderAnnotations = annotations;
return this;
}
public Builder addEntry(KeyStatus status, int keyId, Parameters parameters) {
if (builderEntries == null) {
throw new IllegalStateException("addEntry cannot be called after build()");
}
builderEntries.add(new Entry(status, keyId, parameters));
return this;
}
public Builder setPrimaryKeyId(int primaryKeyId) {
if (builderEntries == null) {
throw new IllegalStateException("setPrimaryKeyId cannot be called after build()");
}
builderPrimaryKeyId = primaryKeyId;
return this;
}
private boolean isKeyIdInEntries(int keyId) {
for (Entry entry : builderEntries) {
if (entry.getKeyId() == keyId) {
return true;
}
}
return false;
}
/** Builds the MonitoringKeysetInfo object. The builder is not usable anymore afterwards. */
public MonitoringKeysetInfo build() throws GeneralSecurityException {
if (builderEntries == null) {
throw new IllegalStateException("cannot call build() twice");
}
if (builderPrimaryKeyId != null) {
// We allow the primary key to not be set. But if it is set, we verify that it is present in
// the keyset.
if (!isKeyIdInEntries(builderPrimaryKeyId.intValue())) {
throw new GeneralSecurityException("primary key ID is not present in entries");
}
}
MonitoringKeysetInfo output =
new MonitoringKeysetInfo(
builderAnnotations,
Collections.unmodifiableList(builderEntries),
builderPrimaryKeyId);
// Collections.unmodifiableMap/List only gives an unmodifiable view of the underlying
// collection. To make output immutable, we have to remove the reference to these collections.
// This makes the builder unusable.
builderEntries = null;
return output;
}
}
private final MonitoringAnnotations annotations;
@SuppressWarnings("Immutable")
private final List<Entry> entries;
@Nullable private final Integer primaryKeyId;
private MonitoringKeysetInfo(
MonitoringAnnotations annotations, List<Entry> entries, Integer primaryKeyId) {
this.annotations = annotations;
this.entries = entries;
this.primaryKeyId = primaryKeyId;
}
public static Builder newBuilder() {
return new Builder();
}
public MonitoringAnnotations getAnnotations() {
return annotations;
}
public List<Entry> getEntries() {
return entries;
}
@Nullable
public Integer getPrimaryKeyId() {
return primaryKeyId;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MonitoringKeysetInfo)) {
return false;
}
MonitoringKeysetInfo info = (MonitoringKeysetInfo) obj;
return annotations.equals(info.annotations)
&& entries.equals(info.entries)
&& Objects.equals(primaryKeyId, info.primaryKeyId);
}
@Override
public int hashCode() {
return Objects.hash(annotations, entries);
}
@Override
public String toString() {
return String.format(
"(annotations=%s, entries=%s, primaryKeyId=%s)", annotations, entries, primaryKeyId);
}
}