github.com/hashicorp/vault/sdk@v0.13.0/plugin/pb/backend.proto (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  syntax = "proto3";
     5  package pb;
     6  
     7  import "google/protobuf/timestamp.proto";
     8  import "sdk/logical/event.proto";
     9  import "sdk/logical/identity.proto";
    10  import "sdk/logical/plugin.proto";
    11  
    12  option go_package = "github.com/hashicorp/vault/sdk/plugin/pb";
    13  
    14  message Empty {}
    15  
    16  message Header {
    17    repeated string header = 1;
    18  }
    19  
    20  message ProtoError {
    21    // Error type can be one of:
    22    // ErrTypeUnknown uint32 = iota
    23    // ErrTypeUserError
    24    // ErrTypeInternalError
    25    // ErrTypeCodedError
    26    // ErrTypeStatusBadRequest
    27    // ErrTypeUnsupportedOperation
    28    // ErrTypeUnsupportedPath
    29    // ErrTypeInvalidRequest
    30    // ErrTypePermissionDenied
    31    // ErrTypeMultiAuthzPending
    32    // ErrTypeUnrecoverable
    33    uint32 err_type = 1;
    34    string err_msg = 2;
    35    int64 err_code = 3;
    36  }
    37  
    38  // Paths is the structure of special paths that is used for SpecialPaths.
    39  message Paths {
    40    // Root are the paths that require a root token to access
    41    repeated string root = 1;
    42  
    43    // Unauthenticated are the paths that can be accessed without any auth.
    44    repeated string unauthenticated = 2;
    45  
    46    // LocalStorage are paths (prefixes) that are local to this instance; this
    47    // indicates that these paths should not be replicated
    48    repeated string local_storage = 3;
    49  
    50    // SealWrapStorage are storage paths that, when using a capable seal,
    51    // should be seal wrapped with extra encryption. It is exact matching
    52    // unless it ends with '/' in which case it will be treated as a prefix.
    53    repeated string seal_wrap_storage = 4;
    54  
    55    // WriteForwardedStorage are storage paths that, when running on a PR
    56    // Secondary cluster, cause a GRPC call up to the PR Primary cluster's
    57    // active node to handle storage.Put(...) and storage.Delete(...) events.
    58    //
    59    // See extended note in /sdk/logical/logical.go.
    60    repeated string write_forwarded_storage = 5;
    61  
    62    // Binary are paths whose request bodies are binary, not JSON
    63    //
    64    // See note in /sdk/logical/logical.go.
    65    repeated string binary = 6;
    66  
    67    // Limited paths are storage paths that require special-case request limiting.
    68    //
    69    // See note in /sdk/logical/logical.go.
    70    repeated string limited = 7;
    71  }
    72  
    73  message Request {
    74    // Id is the uuid associated with each request
    75    string id = 1;
    76  
    77    // If set, the name given to the replication secondary where this request
    78    // originated
    79    string ReplicationCluster = 2;
    80  
    81    // Operation is the requested operation type
    82    string operation = 3;
    83  
    84    // Path is the part of the request path not consumed by the
    85    // routing. As an example, if the original request path is "prod/aws/foo"
    86    // and the AWS logical backend is mounted at "prod/aws/", then the
    87    // final path is "foo" since the mount prefix is trimmed.
    88    string path = 4;
    89  
    90    // Request data is a JSON object that must have keys with string type.
    91    string data = 5;
    92  
    93    // Secret will be non-nil only for Revoke and Renew operations
    94    // to represent the secret that was returned prior.
    95    Secret secret = 6;
    96  
    97    // Auth will be non-nil only for Renew operations
    98    // to represent the auth that was returned prior.
    99    Auth auth = 7;
   100  
   101    // Headers will contain the http headers from the request. This value will
   102    // be used in the audit broker to ensure we are auditing only the allowed
   103    // headers.
   104    map<string, Header> headers = 8;
   105  
   106    // ClientToken is provided to the core so that the identity
   107    // can be verified and ACLs applied. This value is passed
   108    // through to the logical backends but after being salted and
   109    // hashed.
   110    string client_token = 9;
   111  
   112    // ClientTokenAccessor is provided to the core so that the it can get
   113    // logged as part of request audit logging.
   114    string client_token_accessor = 10;
   115  
   116    // DisplayName is provided to the logical backend to help associate
   117    // dynamic secrets with the source entity. This is not a sensitive
   118    // name, but is useful for operators.
   119    string display_name = 11;
   120  
   121    // MountPoint is provided so that a logical backend can generate
   122    // paths relative to itself. The `Path` is effectively the client
   123    // request path with the MountPoint trimmed off.
   124    string mount_point = 12;
   125  
   126    // MountType is provided so that a logical backend can make decisions
   127    // based on the specific mount type (e.g., if a mount type has different
   128    // aliases, generating different defaults depending on the alias)
   129    string mount_type = 13;
   130  
   131    // MountAccessor is provided so that identities returned by the authentication
   132    // backends can be tied to the mount it belongs to.
   133    string mount_accessor = 14;
   134  
   135    // WrapInfo contains requested response wrapping parameters
   136    RequestWrapInfo wrap_info = 15;
   137  
   138    // ClientTokenRemainingUses represents the allowed number of uses left on the
   139    // token supplied
   140    int64 client_token_remaining_uses = 16;
   141  
   142    // EntityID is the identity of the caller extracted out of the token used
   143    // to make this request
   144    string entity_id = 17;
   145  
   146    // PolicyOverride indicates that the requestor wishes to override
   147    // soft-mandatory Sentinel policies
   148    bool policy_override = 18;
   149  
   150    // Whether the request is unauthenticated, as in, had no client token
   151    // attached. Useful in some situations where the client token is not made
   152    // accessible.
   153    bool unauthenticated = 19;
   154  
   155    // Connection will be non-nil only for credential providers to
   156    // inspect the connection information and potentially use it for
   157    // authentication/protection.
   158    Connection connection = 20;
   159  }
   160  
   161  message Auth {
   162    LeaseOptions lease_options = 1;
   163  
   164    // InternalData is a JSON object that is stored with the auth struct.
   165    // This will be sent back during a Renew/Revoke for storing internal data
   166    // used for those operations.
   167    string internal_data = 2;
   168  
   169    // DisplayName is a non-security sensitive identifier that is
   170    // applicable to this Auth. It is used for logging and prefixing
   171    // of dynamic secrets. For example, DisplayName may be "armon" for
   172    // the github credential backend. If the client token is used to
   173    // generate a SQL credential, the user may be "github-armon-uuid".
   174    // This is to help identify the source without using audit tables.
   175    string display_name = 3;
   176  
   177    // Policies is the list of policies that the authenticated user
   178    // is associated with.
   179    repeated string policies = 4;
   180  
   181    // Metadata is used to attach arbitrary string-type metadata to
   182    // an authenticated user. This metadata will be outputted into the
   183    // audit log.
   184    map<string, string> metadata = 5;
   185  
   186    // ClientToken is the token that is generated for the authentication.
   187    // This will be filled in by Vault core when an auth structure is
   188    // returned. Setting this manually will have no effect.
   189    string client_token = 6;
   190  
   191    // Accessor is the identifier for the ClientToken. This can be used
   192    // to perform management functionalities (especially revocation) when
   193    // ClientToken in the audit logs are obfuscated. Accessor can be used
   194    // to revoke a ClientToken and to lookup the capabilities of the ClientToken,
   195    // both without actually knowing the ClientToken.
   196    string accessor = 7;
   197  
   198    // Period indicates that the token generated using this Auth object
   199    // should never expire. The token should be renewed within the duration
   200    // specified by this period.
   201    int64 period = 8;
   202  
   203    // Number of allowed uses of the issued token
   204    int64 num_uses = 9;
   205  
   206    // EntityID is the identifier of the entity in identity store to which the
   207    // identity of the authenticating client belongs to.
   208    string entity_id = 10;
   209  
   210    // Alias is the information about the authenticated client returned by
   211    // the auth backend
   212    logical.Alias alias = 11;
   213  
   214    // GroupAliases are the informational mappings of external groups which an
   215    // authenticated user belongs to. This is used to check if there are
   216    // mappings groups for the group aliases in identity store. For all the
   217    // matching groups, the entity ID of the user will be added.
   218    repeated logical.Alias group_aliases = 12;
   219  
   220    // If set, restricts usage of the certificates to client IPs falling within
   221    // the range of the specified CIDR(s).
   222    repeated string bound_cidrs = 13;
   223  
   224    // TokenPolicies and IdentityPolicies break down the list in Policies to
   225    // help determine where a policy was sourced
   226    repeated string token_policies = 14;
   227    repeated string identity_policies = 15;
   228  
   229    // Explicit maximum lifetime for the token. Unlike normal TTLs, the maximum
   230    // TTL is a hard limit and cannot be exceeded, also counts for periodic tokens.
   231    int64 explicit_max_ttl = 16;
   232  
   233    // TokenType is the type of token being requested
   234    uint32 token_type = 17;
   235  
   236    // Whether the default policy should be added automatically by core
   237    bool no_default_policy = 18;
   238  }
   239  
   240  message TokenEntry {
   241    string id = 1;
   242    string accessor = 2;
   243    string parent = 3;
   244    repeated string policies = 4;
   245    string path = 5;
   246    map<string, string> meta = 6;
   247    string display_name = 7;
   248    int64 num_uses = 8;
   249    int64 creation_time = 9;
   250    int64 ttl = 10;
   251    int64 explicit_max_ttl = 11;
   252    string role = 12;
   253    int64 period = 13;
   254    string entity_id = 14;
   255    repeated string bound_cidrs = 15;
   256    string namespace_id = 16;
   257    string cubbyhole_id = 17;
   258    uint32 type = 18;
   259    map<string, string> internal_meta = 19;
   260    string inline_policy = 20;
   261    bool no_identity_policies = 21;
   262    string external_id = 22;
   263  }
   264  
   265  message LeaseOptions {
   266    int64 TTL = 1;
   267  
   268    bool renewable = 2;
   269  
   270    int64 increment = 3;
   271  
   272    google.protobuf.Timestamp issue_time = 4;
   273  
   274    int64 MaxTTL = 5;
   275  }
   276  
   277  message Secret {
   278    LeaseOptions lease_options = 1;
   279  
   280    // InternalData is a JSON object that is stored with the secret.
   281    // This will be sent back during a Renew/Revoke for storing internal data
   282    // used for those operations.
   283    string internal_data = 2;
   284  
   285    // LeaseID is the ID returned to the user to manage this secret.
   286    // This is generated by Vault core. Any set value will be ignored.
   287    // For requests, this will always be blank.
   288    string lease_id = 3;
   289  }
   290  
   291  message Response {
   292    // Secret, if not nil, denotes that this response represents a secret.
   293    Secret secret = 1;
   294  
   295    // Auth, if not nil, contains the authentication information for
   296    // this response. This is only checked and means something for
   297    // credential backends.
   298    Auth auth = 2;
   299  
   300    // Response data is a JSON object that must have string keys. For
   301    // secrets, this data is sent down to the user as-is. To store internal
   302    // data that you don't want the user to see, store it in
   303    // Secret.InternalData.
   304    string data = 3;
   305  
   306    // Redirect is an HTTP URL to redirect to for further authentication.
   307    // This is only valid for credential backends. This will be blanked
   308    // for any logical backend and ignored.
   309    string redirect = 4;
   310  
   311    // Warnings allow operations or backends to return warnings in response
   312    // to user actions without failing the action outright.
   313    repeated string warnings = 5;
   314  
   315    // Information for wrapping the response in a cubbyhole
   316    ResponseWrapInfo wrap_info = 6;
   317  
   318    // Headers will contain the http headers from the response. This value will
   319    // be used in the audit broker to ensure we are auditing only the allowed
   320    // headers.
   321    map<string, Header> headers = 7;
   322  
   323    // MountType, if non-empty, provides some information about what kind
   324    // of mount this secret came from.
   325    string mount_type = 8;
   326  }
   327  
   328  message ResponseWrapInfo {
   329    // Setting to non-zero specifies that the response should be wrapped.
   330    // Specifies the desired TTL of the wrapping token.
   331    int64 TTL = 1;
   332  
   333    // The token containing the wrapped response
   334    string token = 2;
   335  
   336    // The token accessor for the wrapped response token
   337    string accessor = 3;
   338  
   339    // The creation time. This can be used with the TTL to figure out an
   340    // expected expiration.
   341    google.protobuf.Timestamp creation_time = 4;
   342  
   343    // If the contained response is the output of a token creation call, the
   344    // created token's accessor will be accessible here
   345    string wrapped_accessor = 5;
   346  
   347    // WrappedEntityID is the entity identifier of the caller who initiated the
   348    // wrapping request
   349    string wrapped_entity_id = 6;
   350  
   351    // The format to use. This doesn't get returned, it's only internal.
   352    string format = 7;
   353  
   354    // CreationPath is the original request path that was used to create
   355    // the wrapped response.
   356    string creation_path = 8;
   357  
   358    // Controls seal wrapping behavior downstream for specific use cases
   359    bool seal_wrap = 9;
   360  }
   361  
   362  message RequestWrapInfo {
   363    // Setting to non-zero specifies that the response should be wrapped.
   364    // Specifies the desired TTL of the wrapping token.
   365    int64 TTL = 1;
   366  
   367    // The format to use for the wrapped response; if not specified it's a bare
   368    // token
   369    string format = 2;
   370  
   371    // A flag to conforming backends that data for a given request should be
   372    // seal wrapped
   373    bool seal_wrap = 3;
   374  }
   375  
   376  // HandleRequestArgs is the args for HandleRequest method.
   377  message HandleRequestArgs {
   378    uint32 storage_id = 1;
   379    Request request = 2;
   380  }
   381  
   382  // HandleRequestReply is the reply for HandleRequest method.
   383  message HandleRequestReply {
   384    Response response = 1;
   385    ProtoError err = 2;
   386  }
   387  
   388  // InitializeArgs is the args for Initialize method.
   389  message InitializeArgs {}
   390  
   391  // InitializeReply is the reply for Initialize method.
   392  message InitializeReply {
   393    ProtoError err = 1;
   394  }
   395  
   396  // SpecialPathsReply is the reply for SpecialPaths method.
   397  message SpecialPathsReply {
   398    Paths paths = 1;
   399  }
   400  
   401  // HandleExistenceCheckArgs is the args for HandleExistenceCheck method.
   402  message HandleExistenceCheckArgs {
   403    uint32 storage_id = 1;
   404    Request request = 2;
   405  }
   406  
   407  // HandleExistenceCheckReply is the reply for HandleExistenceCheck method.
   408  message HandleExistenceCheckReply {
   409    bool check_found = 1;
   410    bool exists = 2;
   411    ProtoError err = 3;
   412  }
   413  
   414  // SetupArgs is the args for Setup method.
   415  message SetupArgs {
   416    uint32 broker_id = 1;
   417    map<string, string> Config = 2;
   418    string backendUUID = 3;
   419  }
   420  
   421  // SetupReply is the reply for Setup method.
   422  message SetupReply {
   423    string err = 1;
   424  }
   425  
   426  // TypeReply is the reply for the Type method.
   427  message TypeReply {
   428    uint32 type = 1;
   429  }
   430  
   431  message InvalidateKeyArgs {
   432    string key = 1;
   433  }
   434  
   435  // Backend is the interface that plugins must satisfy. The plugin should
   436  // implement the server for this service. Requests will first run the
   437  // HandleExistenceCheck rpc then run the HandleRequests rpc.
   438  service Backend {
   439    // HandleRequest is used to handle a request and generate a response.
   440    // The plugins must check the operation type and handle appropriately.
   441    rpc HandleRequest(HandleRequestArgs) returns (HandleRequestReply);
   442  
   443    // SpecialPaths is a list of paths that are special in some way.
   444    // See PathType for the types of special paths. The key is the type
   445    // of the special path, and the value is a list of paths for this type.
   446    // This is not a regular expression but is an exact match. If the path
   447    // ends in '*' then it is a prefix-based match. The '*' can only appear
   448    // at the end.
   449    rpc SpecialPaths(Empty) returns (SpecialPathsReply);
   450  
   451    // HandleExistenceCheck is used to handle a request and generate a response
   452    // indicating whether the given path exists or not; this is used to
   453    // understand whether the request must have a Create or Update capability
   454    // ACL applied. The first bool indicates whether an existence check
   455    // function was found for the backend; the second indicates whether, if an
   456    // existence check function was found, the item exists or not.
   457    rpc HandleExistenceCheck(HandleExistenceCheckArgs) returns (HandleExistenceCheckReply);
   458  
   459    // Cleanup is invoked during an unmount of a backend to allow it to
   460    // handle any cleanup like connection closing or releasing of file handles.
   461    // Cleanup is called right before Vault closes the plugin process.
   462    rpc Cleanup(Empty) returns (Empty);
   463  
   464    // InvalidateKey may be invoked when an object is modified that belongs
   465    // to the backend. The backend can use this to clear any caches or reset
   466    // internal state as needed.
   467    rpc InvalidateKey(InvalidateKeyArgs) returns (Empty);
   468  
   469    // Setup is used to set up the backend based on the provided backend
   470    // configuration. The plugin's setup implementation should use the provided
   471    // broker_id to create a connection back to Vault for use with the Storage
   472    // and SystemView clients.
   473    rpc Setup(SetupArgs) returns (SetupReply);
   474  
   475    // Initialize is invoked just after mounting a backend to allow it to
   476    // handle any initialization tasks that need to be performed.
   477    rpc Initialize(InitializeArgs) returns (InitializeReply);
   478  
   479    // Type returns the BackendType for the particular backend
   480    rpc Type(Empty) returns (TypeReply);
   481  }
   482  
   483  message StorageEntry {
   484    string key = 1;
   485    bytes value = 2;
   486    bool seal_wrap = 3;
   487  }
   488  
   489  message StorageListArgs {
   490    string prefix = 1;
   491  }
   492  
   493  message StorageListReply {
   494    repeated string keys = 1;
   495    string err = 2;
   496  }
   497  
   498  message StorageGetArgs {
   499    string key = 1;
   500  }
   501  
   502  message StorageGetReply {
   503    StorageEntry entry = 1;
   504    string err = 2;
   505  }
   506  
   507  message StoragePutArgs {
   508    StorageEntry entry = 1;
   509  }
   510  
   511  message StoragePutReply {
   512    string err = 1;
   513  }
   514  
   515  message StorageDeleteArgs {
   516    string key = 1;
   517  }
   518  
   519  message StorageDeleteReply {
   520    string err = 1;
   521  }
   522  
   523  // Storage is the way that plugins are able read/write data. Plugins should
   524  // implement the client for this service.
   525  service Storage {
   526    rpc List(StorageListArgs) returns (StorageListReply);
   527    rpc Get(StorageGetArgs) returns (StorageGetReply);
   528    rpc Put(StoragePutArgs) returns (StoragePutReply);
   529    rpc Delete(StorageDeleteArgs) returns (StorageDeleteReply);
   530  }
   531  
   532  message TTLReply {
   533    int64 TTL = 1;
   534  }
   535  
   536  message TaintedReply {
   537    bool tainted = 1;
   538  }
   539  
   540  message CachingDisabledReply {
   541    bool disabled = 1;
   542  }
   543  
   544  message ReplicationStateReply {
   545    int32 state = 1;
   546  }
   547  
   548  message ResponseWrapDataArgs {
   549    string data = 1;
   550    int64 TTL = 2;
   551    bool JWT = 3;
   552  }
   553  
   554  message ResponseWrapDataReply {
   555    ResponseWrapInfo wrap_info = 1;
   556    string err = 2;
   557  }
   558  
   559  message MlockEnabledReply {
   560    bool enabled = 1;
   561  }
   562  
   563  message LocalMountReply {
   564    bool local = 1;
   565  }
   566  
   567  message EntityInfoArgs {
   568    string entity_id = 1;
   569  }
   570  
   571  message EntityInfoReply {
   572    logical.Entity entity = 1;
   573    string err = 2;
   574  }
   575  
   576  message GroupsForEntityReply {
   577    repeated logical.Group groups = 1;
   578    string err = 2;
   579  }
   580  
   581  message PluginEnvReply {
   582    logical.PluginEnvironment plugin_environment = 1;
   583    string err = 2;
   584  }
   585  
   586  message GeneratePasswordFromPolicyRequest {
   587    string policy_name = 1;
   588  }
   589  
   590  message GeneratePasswordFromPolicyReply {
   591    string password = 1;
   592  }
   593  
   594  message ClusterInfoReply {
   595    string cluster_name = 1;
   596    string cluster_id = 2;
   597    string err = 3;
   598  }
   599  
   600  message GenerateIdentityTokenRequest {
   601    string audience = 1;
   602    int64 ttl = 2;
   603  }
   604  
   605  message GenerateIdentityTokenResponse {
   606    string token = 1;
   607    int64 ttl = 2;
   608  }
   609  
   610  // SystemView exposes system configuration information in a safe way for plugins
   611  // to consume. Plugins should implement the client for this service.
   612  service SystemView {
   613    // DefaultLeaseTTL returns the default lease TTL set in Vault configuration
   614    rpc DefaultLeaseTTL(Empty) returns (TTLReply);
   615  
   616    // MaxLeaseTTL returns the max lease TTL set in Vault configuration; backend
   617    // authors should take care not to issue credentials that last longer than
   618    // this value, as Vault will revoke them
   619    rpc MaxLeaseTTL(Empty) returns (TTLReply);
   620  
   621    // Tainted, returns true if the mount is tainted. A mount is tainted if it is in the
   622    // process of being unmounted. This should only be used in special
   623    // circumstances; a primary use-case is as a guard in revocation functions.
   624    // If revocation of a backend's leases fails it can keep the unmounting
   625    // process from being successful. If the reason for this failure is not
   626    // relevant when the mount is tainted (for instance, saving a CRL to disk
   627    // when the stored CRL will be removed during the unmounting process
   628    // anyways), we can ignore the errors to allow unmounting to complete.
   629    rpc Tainted(Empty) returns (TaintedReply);
   630  
   631    // CachingDisabled returns true if caching is disabled. If true, no caches
   632    // should be used, despite known slowdowns.
   633    rpc CachingDisabled(Empty) returns (CachingDisabledReply);
   634  
   635    // ReplicationState indicates the state of cluster replication
   636    rpc ReplicationState(Empty) returns (ReplicationStateReply);
   637  
   638    // ResponseWrapData wraps the given data in a cubbyhole and returns the
   639    // token used to unwrap.
   640    rpc ResponseWrapData(ResponseWrapDataArgs) returns (ResponseWrapDataReply);
   641  
   642    // MlockEnabled returns the configuration setting for enabling mlock on
   643    // plugins.
   644    rpc MlockEnabled(Empty) returns (MlockEnabledReply);
   645  
   646    // LocalMount, when run from a system view attached to a request, indicates
   647    // whether the request is affecting a local mount or not
   648    rpc LocalMount(Empty) returns (LocalMountReply);
   649  
   650    // EntityInfo returns the basic entity information for the given entity id
   651    rpc EntityInfo(EntityInfoArgs) returns (EntityInfoReply);
   652  
   653    // PluginEnv returns Vault environment information used by plugins
   654    rpc PluginEnv(Empty) returns (PluginEnvReply);
   655  
   656    // GroupsForEntity returns the group membership information for the given
   657    // entity id
   658    rpc GroupsForEntity(EntityInfoArgs) returns (GroupsForEntityReply);
   659  
   660    // GeneratePasswordFromPolicy generates a password from an existing password policy
   661    rpc GeneratePasswordFromPolicy(GeneratePasswordFromPolicyRequest) returns (GeneratePasswordFromPolicyReply);
   662  
   663    // ClusterInfo returns the ClusterID information; may be reused if ClusterName is also exposed.
   664    rpc ClusterInfo(Empty) returns (ClusterInfoReply);
   665  
   666    // GenerateIdentityToken returns an identity token for the requesting plugin.
   667    rpc GenerateIdentityToken(GenerateIdentityTokenRequest) returns (GenerateIdentityTokenResponse);
   668  }
   669  
   670  message Connection {
   671    // RemoteAddr is the network address that sent the request.
   672    string remote_addr = 1;
   673  
   674    // RemotePort is the network port that sent the request.
   675    int32 remote_port = 3;
   676  
   677    // ConnectionState is the marshalled tls.ConnectionState from the original
   678    // request
   679    ConnectionState connection_state = 2;
   680  }
   681  
   682  message ConnectionState {
   683    uint32 version = 1;
   684    bool handshake_complete = 2;
   685    bool did_resume = 3;
   686    uint32 cipher_suite = 4;
   687    string negotiated_protocol = 5;
   688    bool negotiated_protocol_is_mutual = 6;
   689    string server_name = 7;
   690    CertificateChain peer_certificates = 8;
   691  
   692    repeated CertificateChain verified_chains = 9;
   693    repeated bytes signed_certificate_timestamps = 10;
   694  
   695    bytes ocsp_response = 11;
   696    bytes tls_unique = 12;
   697  }
   698  
   699  message Certificate {
   700    bytes asn1_data = 1;
   701  }
   702  
   703  message CertificateChain {
   704    repeated Certificate certificates = 1;
   705  }
   706  
   707  message SendEventRequest {
   708    string event_type = 1;
   709    logical.EventData event = 2;
   710  }
   711  
   712  service Events {
   713    rpc SendEvent(SendEventRequest) returns (Empty);
   714  }