From 0788ed700931903bf29c4043dd5b8e536a979584 Mon Sep 17 00:00:00 2001 From: Michael McAtee Date: Thu, 16 Jan 2020 15:52:21 -0600 Subject: [PATCH] Updating README.md --- README.md | 1182 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 1075 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 4401ef3..cd2ce6b 100644 --- a/README.md +++ b/README.md @@ -70,55 +70,101 @@ At this point Red October should be serving an example webapp. Access it using y The server exposes several JSON API endpoints. JSON of the prescribed format is POSTed and JSON is returned. - - `/create`: Create the first admin account. - - `/delegate`: Delegate a password to Red October - - `/create-user`: Create a user - - `/modify`: Modify permissions - - `/encrypt`: Encrypt - - `/decrypt`: Decrypt - - `/owners`: List owners of an encrypted secret. - - `/summary`: Display summary of the delegates - - `/password`: Change password - - `/index`: Optionally, the server can host a static HTML file. +| Path | Summary | +| ---- | ------- | +| [`/create`](#create) | Create the first admin account | +| [`/create-user`](#create-user) | Create a user | +| [`/summary`](#summary) | Display summary of the delegated keys and Red October users | +| [`/delegate`](#delegate) | Delegate a key to Red October | +| [`/purge`](#purge) | Delete all delegated keys | +| [`/password`](#password) | Change password for the authenticating user | +| [`/encrypt`](#encrypt) | Encrypt provided data with specified owners and predicates | +| [`/re-encrypt`](#re-encrypt) | Change encryption parameters of already encrypted data (delegation requirements must be met) | +| [`/decrypt`](#decrypt) | Decrypt provided data assuming necesary delegation requirements have been met | +| [`/ssh-sign-with`](#ssh-sign-with) | Sign data as an SSH oracle without disclosing the SSH private key (delegation requirements must be met) | +| [`/owners`](#owners) | List owners (those who can delegate to allow decryption) of a provided encrypted secret | +| [`/modify`](#modify) | Modify an existing user (`delete`, set `admin` flag, `revoke` admin flag) | +| [`/export`](#export) | Exports the internal vault contained encrypted user private keys, hashed passwords, public keys and other RO internal data | +| [`/order`](#order) | Adds an `Order` request to delegate credentials with specific parameters requested | +| [`/orderout`](#orders-outstanding) | Returns a list of `Order` structures for all outstanding orders | +| [`/orderinfo`](#order-information) | Returns the `Order` structure for a specified `OrderNum` | +| [`/ordercancel`](#order-cancel) | Cancel the `Order` with the specified `OrderNum` | +| [`/restore`](#restore) | Restore delegations from a persisted state (if configured). Operates like a `/delegate` call | +| [`/reset-persisted`](#reset-persisted) | Deletes all delegations from the persisted state (if configured) | +| [`/status`](#status) | Returns the status of the persistent store of delegated keys (if configured) | +| [`/index`](#web-interface) | Optionally, the server can host a static HTML file | ### Create -Create is the necessary first call to a new vault. It creates an -admin account. +Create is the necessary first call to a new vault. It creates an admin account. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| No | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password" +} +``` +- `Name` must start with an alphnumeric character and then can contain any alphanumeric character, '-', or '_' after the first character (required) +- `Password` must be at least one character long (required) + +#### Response: +```json +{ + "Status": "ok" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +#### Assumptions: +- This API call can **only** be called on an uninitialized vault and will fail on any call after the first user is created. +- The user created with this call is an **Admin** account. +- This user will use the `passvault.DefaultRecordType`, which is RSA. + +#### Example query: $ curl --cacert cert/server.crt https://localhost:8080/create \ -d '{"Name":"Alice","Password":"Lewis"}' {"Status":"ok"} -### Delegate - -Delegate allows a user to delegate their decryption password to the -server for a fixed period of time and for a fixed number of -decryptions. If the user's account is not created, it creates it. -Any new delegation overrides the previous delegation. - -Example query: - - $ curl --cacert cert/server.crt https://localhost:8080/delegate \ - -d '{"Name":"Bill","Password":"Lizard","Time":"2h34m","Uses":3}' - {"Status":"ok"} - $ curl --cacert cert/server.crt https://localhost:8080/delegate \ - -d '{"Name":"Cat","Password":"Cheshire","Time":"2h34m","Uses":3}' - {"Status":"ok"} - $ curl --cacert cert/server.crt https://localhost:8080/delegate \ - -d '{"Name":"Dodo","Password":"Dodgson","Time":"2h34m","Uses":3}' - {"Status":"ok"} - ### Create User -Create Users creates a new user account. Allows an optional "UserType" -to be specified which controls how the record is encrypted. This can have -a value of either "RSA" or "ECC" and if none is provided will default to -"RSA". +Create User creates a new user account. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| No | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "UserType": "ECC", + "HipchatName": "" +} +``` +- `Name` must be unique within the RedOctober vault (required) +- `Password` must be at least one character long (required) +- `UserType` can be `"RSA"` or `"ECC"` (optional, will default to `"RSA"`) +- `HipchatName` specifies the HipChat username for `Order` notifications if configured (optional) + +#### Response: +```json +{ + "Status": "ok", +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +#### Assumptions: +- Anyone who can access the API, can register a user with this API call. + +#### Example query: $ curl --cacert cert/server.crt https://localhost:8080/create-user \ -d '{"Name":"Bill","Password":"Lizard","UserType":"ECC"}' @@ -130,7 +176,72 @@ Summary provides a list of the users with keys on the system, and a list of users who have currently delegated their key to the server. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok", + "State": "", + "Live": { + "User1": { + "Uses": 1, + "Labels": ["", ""], + "Users": ["", ""], + "Expiry": "", + "AltNames": { + "key1": "value1", + "key2": "value2" + }, + "Admin": true, + "Type": "RSA" + }, + "User1-slot1": { + "Uses": 1, + "Labels": ["", ""], + "Users": ["", ""], + "Expiry": "", + "AltNames": { + "key1": "value1", + "key2": "value2" + }, + "Admin": true, + "Type": "ECC" + }, + }, + "All": { + "User1": { + "Admin": true, + "Type": "RSA" + } + } +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `State` could be `active`, `inactive`, or `disabled` and is the status of the persisted keycache (delegated credentials) +- `Live` is a map of active delegations + - The key is a combination of the username and a slot string (if provided on delegation) + - The value is an object with details about the user and the specific delegation +- `All` is a map of users with keys in Red October + - The key of the map is the username + - The value is a object that says if the user is an `Admin` and if a "RSA or "ECC" key + is used (`Type`) + +#### Assumptions: +- None + +#### Example query: $ curl --cacert cert/server.crt https://localhost:8080/summary \ -d '{"Name":"Alice","Password":"Lewis"}' @@ -157,6 +268,150 @@ Example query: } } + +### Delegate + +Delegate allows a user to delegate their decryption password to the +server for a fixed period of time and for a fixed number of +decryptions. If the user's account is not created, it creates it. +Any new delegation overrides the previous delegation. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes* | No | + +*See the first assumption for this API call + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "Uses": 1, + "Time": "1h10m5s", + "Slot": "", + "Users": ["User2", "User3"], + "Labels": ["", ""] +} +``` +- `Name` and `Password` are the authentication fields for this request* (required) +- `Uses` is the number of times the delegated credentials can be used for `decryption` or otherwise and must be >= 1 (required) +- `Time` is a duration the delegation is active and must parse with Go's `time.ParseDuration()` (required) +- `Slot` is a string that can be used to allow multiple delegations. This value is passed to the `keycache.Cache`, + which stores delegated user credentails, when a user delegates their credentials. If a user wanted to delegate multiple times with different restrictions, such as allowing one user delegated credentials for `ssh-sign-with` and another user for `decrypt`, + then they should submit different values for `Slot` during each `/delegate` request. (optional) +- `Users` is a list of users that can use this delegation. Values must match the `Name` field used at creation of the user. (optional) +- `Labels` are strings used to match the delegation to whether a encrypted secret can be decrypted. If labels were used in + the encryption then at least one label must match in the delegation from both users. (optional) + +*See the first assumption for this API call + +#### Response: +```json +{ + "Status": "ok" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + + +#### Assumptions: +- This API call will create a user if no user matching the `User` field is found. In that case, the same `User` and `Password` validations as `/create` and `/create-user` are followed. +- `Slot` allows for multiple delegations, but is not a validation of purpose. If two delegations are identical, but with + different `Slot` values, either could be used assuming: + - `Uses` has not reached `0` + - `Time` has not expired + - `Users` contains the user attempting to utilize the delegation +- `Labels` is for the `Order` component of RO only and is not checked when attempting to utilize a delegation + +#### Example query: + + $ curl --cacert cert/server.crt https://localhost:8080/delegate \ + -d '{"Name":"Bill","Password":"Lizard","Time":"2h34m","Uses":3}' + {"Status":"ok"} + $ curl --cacert cert/server.crt https://localhost:8080/delegate \ + -d '{"Name":"Cat","Password":"Cheshire","Time":"2h34m","Uses":3}' + {"Status":"ok"} + $ curl --cacert cert/server.crt https://localhost:8080/delegate \ + -d '{"Name":"Dodo","Password":"Dodgson","Time":"2h34m","Uses":3}' + {"Status":"ok"} + + +### Purge + +Purge deletes all delegated keys in Red October. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | Yes | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +#### Assumptions: +- None + +#### Example input JSON format: + + $ curl --cacert cert/server.crt https://localhost:8080/purge \ + -d '{"Name":"Alice","Password":"Lewis"}' + {"Status":"ok"} + + +### Password + +Password allows a user to change their password. This password change +does not require the previously encrypted files to be re-encrypted. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "NewPassword": "User1Password!NEW", + "HipchatName": "" +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `NewPassword` will replace the current password and must be at least 1 character long (required) +- `HipchatName` is used for the internal HipChat ordering system (optional) + +#### Response: +```json +{ + "Status": "ok" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +#### Assumptions: +- None + +### Example Input JSON format: + + $ curl --cacert cert/server.crt https://localhost:8080/password \ + -d '{"Name":"Bill","Password":"Lizard", "NewPassword": "theLizard"}' + {"Status":"ok"} + ### Encrypt Encrypt allows a user to encrypt a piece of data. A list of valid @@ -165,7 +420,125 @@ decrypt. The returned data can be decrypted as long as "Minimum" number users from the set of "Owners" have delegated their keys to the server. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password", + "Minimum": 2, + "Owners": ["User4", "User3", "Users2"], + "LeftOwners": ["", ""], + "RightOwners": ["", ""], + "Predicate": "", + "Data": "V2h5IGlzIGEgcmF2ZW4gbGlrZSBhIHdyaXRpbmcgZGVzaz8K", + "Labels": ["", ""], + "Usages": ["", ""] +} +``` +- `Name` and `Password` authenticate the request (required) +- `Minimum` is the number of delegations required to decrypt. Should only be 1 or 2 unless using `LeftOwners` and `RightOwners` or + a `Predicate` string. (optional) +- `Owners` is a list of users that if delegated allows decryption of the secret. Need at least `Minimum` users. (required1) +- `LeftOwners` and `RightOwners` are list of users that require delegation of at least one left + and one right (required1) +- `Predicate` is a string that maps to an arbitrary monotone access structure. Please see [MSP Package](https://github.com/cloudflare/redoctober/tree/master/msp) (required1) +- `Data` is the base64 encoded data to be encrypted (required) +- `Labels` are strings that will mark if a decryption can occure based on matching labels in the delegation. If `Labels` is not + empty, then at least one value of `Labels` in the `/delegate` request must match at least one value in this request's `Labels`. (optional) +- `Usages` are strings that define how the secret can be used. Such as if it can be returned by `/decrypt` ["`decrypt`"] or used + to with `/ssh-sign-with` [`"ssh-sign-with"`] (optional) + +1 Either `Owners`, `LeftOwners` and `RightOwners`, or `Predicate` is required. If one of the three is used, the other two should not be provided in the request. + +#### Response: +```json +{ + "Status": "ok", + "Response": "nWY13Rx8d7Tov0AFGu...Hok3DlNnDs8FcrU5/PrxuExq" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` is the base64 encoded JSON object + +If you base64 decode `Response`, you will get: +```json +{ + "Version": -1, + "Data": "c5UHBZ5KYk9K4WIf94Os/n6gtm...hu2aM1+yQO0iwhLC", + "Signature": "Hsd88NiDaA9Ech2uHzDjLA==" +} +``` +- `Version` is always -1 as it is used when HMAC-ing the encrypted data +- `Data` is a base64 encoded JSON object +- `Signature` is the HMAC signature of `Data` + +If you base64 decode `Data`, you will get: +```json +{ + "Version": 1, + "VaultId": 12905318, + "Labels": ["", ""], + "Usages": ["", ""], + "Predicate": "", + "KeySet": [ + { + "Name": ["User1", "User2"], + "Key": "OnfKLlXjk0swCtdc3/GPcQ==" + }, + { + "Name": ["User2", "User3"], + "Key": "BRJ1ZtL0IS1g6fuPAgKkGA==" + }, + ... + ], + "KeySetRSA": [ + "User1": { + "Key": "ZTXz2KehhQ+02umuhSK9pmv3q155FW6BtqDUctz1k0NOI9e9WrL+vg==" + }, + "User2": { + "Key": "R87vNqb7GhxZ8Bl+hd2osnQWVmgs68KmQ8LqoXg/3M3dvfyPBxyujw==" + }, + "User3": { + "Key": "uocoMcwt00sbMM2aqUhKnDdwcyWfj8AxZjUGib8pDSBYl2XfU4gM/A==" + }, + ... + ], + "ShareSet": [ + "User1": ["5tJHlh2P+x9pNwOrjQsqxJMuTN9PdRqiFJ...OFYw/0="], + "User2": ["Hg06yJnUUAjerytV6/iHr/7...bxUB/M8U7FpYDzw="], + ... + ], + "IV": "xyjda++X7+8wQ0VH6Dnt/w==", + "Data": "k9kezvCRTe6x/Fl8pVBxb...Wup5ESrQw553IxIRbY=", + "Signature": "uUXOkuCAbGUSO4u81/ampQ==" +} +``` +- `Version` is the version number of the `EncryptedData` structure +- `VaultId` will be a random 32 bit, non-negative integer identifying the vault +- `Labels` are the same as the request `Labels` +- `Usages` are the same as the request `Usages` +- `Predicate` are the same as the request `Predicate` +- `KeySet` is an array of objects with a `Name` and `Key` attribute. Each object in the array is a encrypted value using + intermediary keys from two users. All validate two user key delegations are stored in this array to allow decryption. + - `Name` is an array of two users that were used to encrypt the `Data` encryption key + - `Key` is a base64 encoded byte array that represents a doubly encrypted key, that was used to encrypt `Data` +- `KeySetRSA` is an map where the key is a user and the value is an object with one attribute `Key`. + - `Key` is the base64 encoded byte array that represents the intermediary key encrypted with a users RSA or ECC public key. + Once decrypted, the intermediary key for two users can be used to decrypt the `Data` encryption key stored in the `KeySet` map. +- `ShareSet` is a map of base64 encoded byte strings representing the distributed shares generated from the requested `Predicate` + - The map key is the user and the value is that users portion of the share +- `IV` is the AES initial vector used +- `Signature` is the internal HMAC signature of this whole structure + +#### Assumptions: +- `KeySet` and `KeySetRSA` will always be populated +- `ShareSet` will only be populated when using `Predicate` + +#### Example query: $ echo "Why is a raven like a writing desk?" | openssl base64 V2h5IGlzIGEgcmF2ZW4gbGlrZSBhIHdyaXRpbmcgZGVzaz8K @@ -183,6 +556,69 @@ Example query with a predicate: The data expansion is not tied to the size of the input. + +### Re-Encrypt + +Re-encrypt allows for modification of encrypted data, without having to call Decrypt and then Encrypt, thus exposing the +secret to the caller. Enough delegation to Decrypt are required for this call to run. A call is very similar to except +instead of base64 encoded data in the `Data` field, provide the `Response` value from a previous `/encrypt` call. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password", + "Minimum": 2, + "Owners": ["User4", "User3", "Users2", "User5"], + "LeftOwners": ["", ""], + "RightOwners": ["", ""], + "Predicate": "", + "Data": "nWY13Rx8d7Tov.../PrxuExq", + "Labels": ["", ""], + "Usages": ["", ""], +} +``` +- `Name` and `Password` authenticate the request (required) +- `Data` is the base64 encoded response from `/encrypt` (required) +- All other fields work similar to a `/encrypt` call and will replace the original calls values + +#### Response: +```json +{ + "Status": "ok", + "Response": "QIsDoh/jp3sky...JfOTePLRAMp7k=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` is the base64 encoded JSON object +- The internal structure of `Response` is identical to the response of an `/encrypt` call + +#### Assumptions: +- Necessary delegations to decrypt the provided encrypted value should already be delegated. + +#### Example query: + + $ echo "Why is a raven like a writing desk?" | openssl base64 + V2h5IGlzIGEgcmF2ZW4gbGlrZSBhIHdyaXRpbmcgZGVzaz8K + + $ curl --cacert cert/server.crt https://localhost:8080/re-encrypt \ + -d '{"Name":"Alice","Password":"Lewis","Minimum":2, "Owners":["Alice","Bill","Cat","Dodo","Greg"],"Data":"eyJWZXJzaW9uIj...NSSllzPSJ9"}' + {"Status":"ok","Response":"J6rv0zlJ7l8stG6Oz...lQu8gXKSoIR6U="} + +Example query with a predicate: + + $ curl --cacert cert/server.crt https://localhost:8080/re-encrypt \ + -d '{"Name":"Alice","Password":"Lewis","Predicate":"Alice & (Bob | Carl | Dodo)", + Data":"eyJWZXJzaW9uIj...NSSllzPSJ9"}' + {"Status":"ok","Response":"J6rv0zlJ7l8stG6Oz...lQu8gXKSoIR6U="} + +The data expansion is not tied to the size of the input. + + ### Decrypt Decrypt allows a user to decrypt a piece of data. As long as @@ -190,7 +626,38 @@ Decrypt allows a user to decrypt a piece of data. As long as keys to the server, a base64 encoded object with the clear data and the set of "Owners" whose private keys were used is returned. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password", + "Data": "nWY13Rx8.../PrxuExq", +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `Data` is the encrypted secret returned be a call to `/encrypt` (required) + +#### Response: +```json +{ + "Data": "V2h5IGlzIGEgcmF2ZW4gbGlrZSBhIHdyaXRpbmcgZGVzaz8K", + "Secure": true, + "Delegates": ["User2", "User3"] +} +``` +- `Data` is the response from an encrypt call to be decrypted +- `Secure` this is a flag that states if the payload was properly HMAC protected +- `Delegates` notes which user's delegated keys were used to decrypt this blob + +#### Assumptions: +- None + +#### Example query: $ curl --cacert cert/server.crt https://localhost:8080/decrypt \ -d '{"Name":"Alice","Password":"Lewis","Data":"eyJWZXJzaW9uIj...NSSllzPSJ9"}' @@ -200,27 +667,107 @@ If there aren't enough keys delegated you'll see: {"Status":"need more delegated keys"} + +### SSH Sign With + +SSHSignWith signs a message with an SSH key previously encrypted with Red October and with a "Usages" containing `ssh-sign-with` + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "Data": "W2Y4QfAd5pf+sqFkvEzEm...p8/Zbo21YWzCNuStzyXfUcBk=", + "TBSData": "fjELOIwcZsloJY...PPIutXm7fBLJHOJwQ8ht+8Mo=" +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `Data` is the encrypted SSH private key (required) +- `TBSData` is the SSH message to be signed by the SSH private key (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "rePs8L+l7xtRY50uuuFZ4As4UQZWgzfLd...q808VFaHZNJ9AIfK0vZ9c=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +If you base64 decode the Response, you will get: +```json +{ + "SignatureFormat": "ssh-rsa-cert-v01@openssh.com", + "Signature": "M02dHSCbE/35H8RrxZmHAA==", + "Secure": true, # boolean + "Delegates": ["User1", "User2"] +} +``` +- `SignatureFormat` is the SSH signature type +- `Signature` is a base64 encoded byte array, which is the signature of the SSH signing operation +- `Secure` whether the HMAC validated or not +- `Delegates` are the user keys used to temporary decrypt the SSH key for signing + +#### Assumptions: +- If a `Usages` value of `ssh-sign-with` was not provided, this function will not work +- If a `Usages` value of `decrypt` is not provided with `ssh-sign-with`, then the SSH key cannot be decrypted via + a `/decrypt` call + - Note that while not providing `decrypt` avoids `/decrypt` returning the unencrypted SSH private key, `/re-encrypt` could + be used to change that with the necessary delegation. + +#### Example query: + + $ curl --cacert cert/server.crt https://localhost:8080/ssh-sign-with \ + -d '{"Name":"Alice","Password":"Lewis","Data":"eyJWZXJzaW9uIj...NSSllzPSJ9","TBSData":"eyJEYXRhI...FuMiJdfQ=="}' + {"Status":"ok","Response":"rePs8L+l7xtRY50uuuFZ4As4UQZWg...FaHZNJ9AIfK0vZ9c="} + + ### Owners Owners allows users to determine which delegations are needed to decrypt a piece of data. -Example query: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| No | No | + + +#### Request: +```json +{ + "Data": "V2h5IGlzIGEgcmF2ZW4gbGlrZSB...hIHdyaXRpbmcgZGVzaz8K==" +} +``` +- `Data` is the response from an encrypt call to be decrypted (required) + +#### Response: +```json +{ + "Status": "ok", + "Owners": ["User1", "User2", "User3"], + "Labels": ["", ""], + "Predicate": "" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Owners` will be all the users that were noted in `Owners`, `LeftOwners`, `RightOwners`, or within the `Predicate` +- `Labels` will match any that were provided in the `/encrypt` call or not be present if empty +- `Predicate` will be the value provied to `/encrypt` or not present if not used in the encryption + +#### Assumptions: +- Anyone with access to an encrypted secret can look this data up in the JSON structure anyway, so it is not an authenticated request + +#### Example query: $ curl --cacert cert/server.crt https://localhost:8080/owners \ -d '{"Data":"eyJWZXJzaW9uIj...NSSllzPSJ9"}' {"Status":"ok","Owners":["Alice","Bill","Cat","Dodo"]} -### Password - -Password allows a user to change their password. This password change -does not require the previously encrypted files to be re-encrypted. - -Example Input JSON format: - - $ curl --cacert cert/server.crt https://localhost:8080/password \ - -d '{"Name":"Bill","Password":"Lizard", "NewPassword": "theLizard"}' - {"Status":"ok"} ### Modify @@ -231,102 +778,523 @@ There are 3 commands: - `admin`: grants admin status to a user - `delete`: removes the account of a user -Example input JSON format: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | Yes | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "ToModify": "User2", + "Command": "admin" +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `ToModify` username to apply the `Command` against (required) +- `Command` can be `revoke`, `admin`, `delete` (required) + +#### Response: +```json +{ + "Status": "ok" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. + +#### Assumptions: +- If a user is deleted, their key can never be delegated again because the key is deleted. If you recreate the user, + delegation will still fail as the keys will be different. + +#### Example input JSON format: $ curl --cacert cert/server.crt https://localhost:8080/modify \ -d '{"Name":"Alice","Password":"Lewis","ToModify":"Bill","Command":"admin"}' {"Status":"ok"} -### Purge -Purge deletes all delegates for an encryption key. +### Export -Example input JSON format: +Export Red October's internal password vault, which contains users' hashed passwords, salts, encrypted private keys and their +public keys. - $ curl --cacert cert/server.crt https://localhost:8080/purge \ - -d '{"Name":"Alice","Password":"Lewis"}' - {"Status":"ok"} +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | Yes | +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "ewogICAgIlZlcnNpb24iOiAxLCAjIG51bWJlcgogI...ICAgIH0KfQo=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` is a base64 encoded JSON object + +If you were to base64 decode `Response`, you would get: +```json +{ + "Version": 1, + "VaultId": 12905318, + "HmacKey": "JaEu/PQTkpFjp2rML8QUbQ==", + "Passwords": { + "User1": { + "Type": "", + "PasswordSalt": "rFQLnQj+5+I6/YPOteDSNw==", + "HashedPassword": "1WCgv8d9uXC9CcPQBQv9qw==", + "KeySalt": "gVDCnhwOMP3obXgv0avBlQ==", + "RSAKey": { + "RSAExp": "jfqESm+...+nMgQM3x34wQmGswfF62MhDk2sTw==", + "RSAExpIV": "gA0/0sS...iKNXVxXGCKXFyBlyGo4g==", + "RSAPrimeP": "xZnZ32YvEhhOV+...boElV9EA9OJvxsyODjQ==", + "RSAPrimePIV": "LneAiwSzMGbym7e7...nL12tcOy/LN4l8uAV8Khw==", + "RSAPrimeQ": "s/cnhyihrUS...sfnyLuxRIb1eL3aYB18dzjn0D0g==", + "RSAPrimeQIV": "S+8+9Q51Ig6/8in31J9y...4GD2BSig==", + "RSAPublic": {"N":707958947...4076221507,"E":65537} + }, + "ECKey": { + "ECPriv":"vzrbL2pj8wxldTb6vYws7cAjIzGdh39TxepIb71GcB0=", + "ECPrivIV": "LPXav82KMgI3pdg30VPvI2cBsk4BQLaylg45NCYR0Bc=", + "ECPublic":{ + "Curve":{ + "P":11579208921035...308867097853951, + "N":11579208925624...259061068512369, + "B":41058363725114...725554835251291, + "Gx":4843956129391...807170824035286, + "Gy":3613425095677...253568414405109, + "BitSize":256, + "Name":"P-256" + }, + "X":1288875298858438030...5394564151993378, + "Y":3728055919617037354...6025371017809918 + }, + "AltNames": { + "": "", + ... + }, + "Admin": true + }, + "User2": { + ... + }, + ... + } +} +``` + +#### Assumptions: +- Only RSAKey or ECKey would be populated in an actual response +- While the user passwords are hashed and and the various internal values of the ECKey and RSAKey are encrypted with the + user's cleartext password, these values are still sensitive and should be handled as such. + +#### Example query: + + $ curl --cacert cert/server.crt https://localhost:8080/export \ + -d '{"Name":"Alice","Password":"Lewis"}' + {"Status":"ok","Response":"ewogICAgIlZlcn...ICAgIH0KfQo="} + ### Order Order creates a new order and lets other users know delegations are needed. -Example input JSON format: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "Duration": "1h10m5s", + "Uses": 2, + "Users": ["User2", "User3"], + "EncryptedData": "nWY13Rx8d7Tov0AFGuf3IINzdHIFD.../PrxuExq", + "Labels": ["", ""] +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `Duration` must be parsable by Go's `time.ParseDuration()` and is the amount of time this `Order` is valid for (required) +- `Uses` is the number of `Uses` required of each user delegation (required) +- `Users` lists the specific user delegations being requested (required) +- `EncryptedData` is the secret that the user delegations will be used against (required) +- `Labels` are specific label requirements for the delegation requests, likely required for `/decrypt` of this specific secret (optional) + +#### Response: +```json +{ + "Status": "ok", + "Response": "ewogICJDcmVhdG9yIjogIlVz...gICAgIiIKICBdCn0K" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object + +If you base64 decode `Response`, you will get: +```json +{ + "Creator": "User1", + "Users": ["User2", "User3"], + "Num": "2ab99e07ff0405961f5e0d10", + "TimeRequested": "2009-11-10T23:00:00Z", + "DurationRequested": 4205000000000, + "Delegated": 1, + "OwnersDelegated": ["User3"], + "Owners": ["User4", "User3", "Users2"], + "Labels": ["", ""] +} +``` +- `Creator` is the user that created the `Order` +- `Users` are the list of users in the `Order` request +- `Num` is a hex encoded random 12 byte value, which is hte `OrderId` +- `TimeRequested` is the time the `Order` was created +- `DurationRequested` is the parsed value of `Duration` in 64 bit number form +- `Delegated` is the number of user key delegations that already exist from those requested in the original request +- `OwnersDelegated` is the users that were found already delegated (this array length will be the same as `Delegated`) +- `Owners` are the users listed as `Owners` in the `EncryptedData` provided in the original request +- `Labels` are the labels included in the original request + +#### Assumptions: +- Orders work with the Hipchat components of Red October, so those should be configured and user details for Hipchat registered + +#### Example input JSON format: $ curl --cacert server/server.crt https://localhost:8080/order \ -d '{"Name":"Alice","Password":"Lewis","Labels": ["Blue","Red"],\ "Duration":"1h","Uses":5,"EncryptedData":"ABCDE=="}' - { - "Admins": [ - "Bob", - "Eve" - ], - "AdminsDelegated": null, - "Delegated": 0, - "DurationRequested": 3.6e+12, - "Labels": [ - "blue", - "red" - ], - "Name": "Alice", - "Num": "77da1cfd8962fb9685c15c84", - "TimeRequested": "2016-01-25T15:58:41.961906679-08:00", - } + {"Status": "ok","Response": "ewogICJDcmVhdG9yIjogIlVzZXIxIiwKICAiVXNlcnMiOiBbCiAgICAiVXNlcjIiLAogICAgIlVzZXIzIgogIF0sCiAgIk51bSI6ICIyYWI5OWUwN2ZmMDQwNTk2MWY1ZTBkMTAiLAogICJUaW1lUmVxdWVzdGVkIjogIjIwMDktMTEtMTBUMjM6MDA6MDBaIiwKICAiRHVyYXRpb25SZXF1ZXN0ZWQiOiA0MjA1MDAwMDAwMDAwLAogICJEZWxlZ2F0ZWQiOiAxLAogICJPd25lcnNEZWxlZ2F0ZWQiOiBbCiAgICAiVXNlcjMiCiAgXSwKICAiT3duZXJzIjogWwogICAgIlVzZXI0IiwKICAgICJVc2VyMyIsCiAgICAiVXNlcnMyIgogIF0sCiAgIkxhYmVscyI6IFsKICAgICIiLAogICAgIiIKICBdCn0K"} ### Orders Outstanding Orders Outstanding will return a list of current order numbers -Example input JSON format: +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "ewogICIyYWI5OWUwN2Z...AgIF0KICB9Cn0K" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object + +If you base64 decode `Response`, you will get: +```json +{ + "2ab99e07ff0405961f5e0d10": { + "Creator": "User1", + "Users": ["User2", "User3"], + "Num": "2ab99e07ff0405961f5e0d10", + "TimeRequested": "2009-11-10T23:00:00Z", + "DurationRequested": 4205000000000, + "Delegated": 1, + "OwnersDelegated": ["User3"], + "Owners": ["User4", "User3", "Users2"], + "Labels": ["", ""] + }, + ... +} +``` +- The object is a map where the `key` is each `Order`'s `Num` (a.k.a. `OrderNum`) and the `value` is the serialized `Order` object + - `Creator` is the user that created the `Order` + - `Users` are the list of users in the `Order` request + - `Num` is a hex encoded random 12 byte value, which is hte `OrderId` + - `TimeRequested` is the time the `Order` was created + - `DurationRequested` is the parsed value of `Duration` in 64 bit number form + - `Delegated` is the number of user key delegations that already exist from those requested in the original request + - `OwnersDelegated` is the users that were found already delegated (this array length will be the same as `Delegated`) + - `Owners` are the users listed as `Owners` in the `EncryptedData` provided in the original request + - `Labels` are the labels included in the original request + +#### Assumptions: +- None + +#### Example input JSON format: $ curl --cacert server/server.crt https://localhost:8080/orderout -d '{"Name":"Alice","Password":"Lewis"}' - { - "77da1cfd8962fb9685c15c84":{ - "Name":"Alice", - "Num":"77da1cfd8962fb9685c15c84", - "TimeRequested":"2016-01-25T15:58:41.961906679-08:00", - "DurationRequested":3600000000000, - "Delegated":0," - AdminsDelegated":null, - "Admins":["Bob, Eve"], - "Labels":["Blue","Red"] - } - } + {"Status": "ok","Response": "ewogICI3N2RhMWNmZDg5NjJmYjk2ODVjMTVjODQiOiB7CiAgICAiTmFtZSI6ICJBbGljZSIsCiAgICAiVXNlcnMiOiBbCiAgICAgICJCb2IiLAogICAgICAiRXZlIgogICAgXSwKICAgICJOdW0iOiAiNzdkYTFjZmQ4OTYyZmI5Njg1YzE1Yzg0IiwKICAgICJUaW1lUmVxdWVzdGVkIjogIjIwMTYtMDEtMjVUMTU6NTg6NDEuOTYxOTA2Njc5LTA4OjAwIiwKICAgICJEdXJhdGlvblJlcXVlc3RlZCI6IDM2MDAwMDAwMDAwMDAsCiAgICAiRGVsZWdhdGVkIjogMCwKICAgICJPd25lcnNEZWxlZ2F0ZWQiOiBbXSwKICAgICJPd25lcnMiOiBbCiAgICAgICJCb2IiLAogICAgICAiRXZlIgogICAgXSwKICAgICJMYWJlbHMiOiBbCiAgICAgICJCbHVlIiwKICAgICAgIlJlZCIKICAgIF0KICB9Cn0K"} ### Order Information -Example input JSON format: +Returns the order information for a specific Order number. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "OrderNum": "2ab99e07ff0405961f5e0d10" +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `OrderNum` is the same value returned as `Num` under and `Order` object (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "ewogICJDcmVhdG9yIjogIlVzZXIxIiwKICAiV...AogICAgIiIKICBdCn0K" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object + +If you base64 decode `Response`, you will get: +```json +{ + "Creator": "User1", + "Users": ["User2", "User3"], + "Num": "2ab99e07ff0405961f5e0d10", + "TimeRequested": "2009-11-10T23:00:00Z", + "DurationRequested": 4205000000000, + "Delegated": 1, + "OwnersDelegated": ["User3"], + "Owners": ["User4", "User3", "Users2"], + "Labels": ["", ""] +} +``` +- `Creator` is the user that created the `Order` +- `Users` are the list of users in the `Order` request +- `Num` is a hex encoded random 12 byte value, which is hte `OrderId` +- `TimeRequested` is the time the `Order` was created +- `DurationRequested` is the parsed value of `Duration` in 64 bit number form +- `Delegated` is the number of user key delegations that already exist from those requested in the original request +- `OwnersDelegated` is the users that were found already delegated (this array length will be the same as `Delegated`) +- `Owners` are the users listed as `Owners` in the `EncryptedData` provided in the original request +- `Labels` are the labels included in the original request + +#### Assumptions: +- None + +#### Example input JSON format: $ curl --cacert server/server.crt https://localhost:8080/orderinfo -d '{"Name":"Alice","Password":"Lewis", \ "OrderNum":"77da1cfd8962fb9685c15c84"}' - { - "Admins": [ - "Bob", - "Eve" - ], - "AdminsDelegated": null, - "Delegated": 0, - "DurationRequested": 3.6e+12, - "Labels": [ - "blue", - "red" - ], - "Name": "Alice", - "Num": "77da1cfd8962fb9685c15c84", - "TimeRequested": "2016-01-25T15:58:41.961906679-08:00" - } + {"Status": "ok","Response": "ewogICJDcmVhdG9yIjogIlVzZXIxIiwKICAiVXNlcnMiOiBbCiAgICAiVXNlcjIiLAogICAgIlVzZXIzIgogIF0sCiAgIk51bSI6ICIyYWI5OWUwN2ZmMDQwNTk2MWY1ZTBkMTAiLAogICJUaW1lUmVxdWVzdGVkIjogIjIwMDktMTEtMTBUMjM6MDA6MDBaIiwKICAiRHVyYXRpb25SZXF1ZXN0ZWQiOiA0MjA1MDAwMDAwMDAwLAogICJEZWxlZ2F0ZWQiOiAxLAogICJPd25lcnNEZWxlZ2F0ZWQiOiBbCiAgICAiVXNlcjMiCiAgXSwKICAiT3duZXJzIjogWwogICAgIlVzZXI0IiwKICAgICJVc2VyMyIsCiAgICAiVXNlcnMyIgogIF0sCiAgIkxhYmVscyI6IFsKICAgICIiLAogICAgIiIKICBdCn0K"} + ### Order Cancel -Example input JSON format: +Removes a given order from Red October's Orderer. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!", + "OrderNum": "2ab99e07ff0405961f5e0d10" +} +``` +- `Name` and `Password` are used to authenticate the request (required) +- `OrderNum` is the same value returned as `Num` under and `Order` object (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "U3VjY2Vzc2Z1bGx5IHJlbW92ZWQgb3JkZXIK" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be the base64 encoded string `"Successfully removed order"` if successful + +#### Assumptions: +- None + +#### Example input JSON format: $ curl --cacert server/server.crt https://localhost:8080/orderinfo -d '{"Name":"Alice","Password":"Lewis", \ "OrderNum":"77da1cfd8962fb9685c15c84"}' - {"Status":"ok"} + {"Status":"ok","Response": "U3VjY2Vzc2Z1bGx5IHJlbW92ZWQgb3JkZXIK"} + + + +### Restore + +Restore is functionally almost identical to Delegate, but for restoring the persisted delegation cache. Once enough calls +to restore are completed to meet the delegation requirements of the persistence configuration, the current delegation cache +will be overwritten with the persisted one. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password", + "Time": "", +} +``` +- `Name` and `Password` are the authentication fields for this request* (required) +- `Time` is a duration the delegation is active and must parse with Go's `time.ParseDuration()` (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "e1N0YXR1czogYWN0aXZlfQo=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object if not empty + +If you base64 decode `Response`, you will get: +```json +{ + "Status": "active" +} +``` +- `Status` could be `active`, `inactive`, or `disabled` + +#### Assumptions: +- This function only does something if the persist module has been configured. + +#### Example query: +On succesful restore + + $ curl --cacert cert/server.crt https://localhost:8080/restore \ + -d '{"Name":"Alice","Password":"Lewis","Time":"1h10m"}' + {"Status":"ok","Response":"e1N0YXR1czogYWN0aXZlfQo="} + +Need more calls to restore to delegate more credentials + + $ curl --cacert cert/server.crt https://localhost:8080/restore \ + -d '{"Name":"Alice","Password":"Lewis","Time":"1h10m"}' + {"Status":"need more delegated keys","Response":""} + +### Reset-Persisted + +Reset-Persisted will clear the persisted delegation data if configured. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | Yes | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "e1N0YXR1czogYWN0aXZlfQo=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object if not empty + +If you base64 decode `Response`, you will get: +```json +{ + "Status": "active" +} +``` +- `Status` could be `active`, `inactive`, or `disabled` + +#### Assumptions: +- None + +#### Example query: + + $ curl --cacert cert/server.crt https://localhost:8080/reset-persisted \ + -d '{"Name":"Alice","Password":"Lewis"}' + {"Status":"ok","Response":"e1N0YXR1czogYWN0aXZlfQo="} + + +### Status + +Status returns the current delegation persistence state. + +| Requires Authentication | Requires Admin | +| ----------------------- | -------------- | +| Yes | No | + + +#### Request: +```json +{ + "Name": "User1", + "Password": "User1Password!" +} +``` +- `Name` and `Password` are used to authenticate the request (required) + +#### Response: +```json +{ + "Status": "ok", + "Response": "e1N0YXR1czogYWN0aXZlfQo=" +} +``` +- `Status` will be `"ok"` if successful or an error string if not. +- `Response` will be a base64 encoded JSON object if not empty + +If you base64 decode `Response`, you will get: +```json +{ + "Status": "active" +} +``` +- `Status` could be `active`, `inactive`, or `disabled` + +#### Assumptions: +- None + +#### Example query: + + $ curl --cacert cert/server.crt https://localhost:8080/status \ + -d '{"Name":"Alice","Password":"Lewis"}' + {"Status":"ok","Response":"e1N0YXR1czogYWN0aXZlfQo="} + + ### Web interface