View on GitHub

iot-identity-service

Source of the Azure IoT Identity Service and related services.

Keys Service

API

An OpenAPI v3 spec for this service can be found at /key/aziot-keyd/openapi/2021-05-01.yaml

Generate New Symmetric Key

POST /key?api-version=2021-05-01

Authentication

Required. See API authentication.

Request

{
    "keyId": "...",
    "usage": "..."
}

usage is a comma-separated sequence of one or more of the following strings:

Eg: "usage": "derive,sign"

Response

{
    "keyHandle": "string"
}

Import Symmetric Key

POST /key?api-version=2021-05-01

Authentication

Required. See API authentication.

Request

{
    "keyId": "...",
    "keyBytes": "base64-encoded-string"
}

Response

{
    "keyHandle": "string"
}

Get Existing Symmetric Key

GET /key/{keyId}?api-version=2021-05-01

Authentication

Required. See API authentication.

Response

{
    "keyHandle": "string"
}

Delete Symmetric Key

DELETE /key?api-version=2021-05-01

Authentication

Not required.

Request

{
    "keyHandle": "..."
}

Response

Empty (HTTP 204)


Generate New Asymmetric Key Pair

POST /keypair?api-version=2021-05-01

Authentication

Required. See API authentication.

Request

{
    "keyId": "string",
    "preferredAlgorithms": "..."
}

Response

{
    "keyHandle": "string"
}

Move Asymmetric Key Pair

POST /keypair/{keyPairId}?api-version=2021-05-01

Authentication

Required. See API authentication.

The caller of this API must be authorized to modify both from and keyPairId.

Request

{
    "from": "string",
}

Response

Empty (HTTP 204)


Get Existing Asymmetric Key Pair

GET /keypair/{keyPairId}?api-version=2021-05-01

Authentication

Required. See API authentication.

Response

{
    "keyHandle": "string"
}

Get Parameter of Asymmetric Key Pair

POST /parameters/{parameterName}?api-version=2021-05-01

Authentication

Not required.

Request

{
    "keyHandle": "string"
}

Response

{
    "value": ...
}

The value of value in the response depends on the parameterName:


Delete Asymmetric Key Pair

DELETE /keypair?api-version=2021-05-01

Authentication

Not required.

Request

{
    "keyHandle": "..."
}

Response

Empty (HTTP 204)


Sign

POST /sign?api-version=2021-05-01

This includes both digital signatures using asymmetric keys and HMAC-SHA256 using symmetric keys.

Authentication

Not required.

Request

ECDSA

Only valid for ECDSA keys.

Note that the request takes the message digest, ie it must be calculated by the client.

{
    "keyHandle": "string",
    "algorithm": "ECDSA",
    "parameters": {
        "digest": "base64-encoded-string",
    }
}
HMAC-SHA256

Only valid for symmetric keys.

{
    "keyHandle": "string",
    "algorithm": "HMAC-SHA256",
    "parameters": {
        "message": "base64-encoded-string"
    }
}

Response

{
    "signature": "base64-encoded-string"
}

Encrypt

POST /encrypt?api-version=2021-05-01

Request

AEAD

Only valid for symmetric keys.

{
    "keyHandle": "string",
    "algorithm": "AEAD",
    "parameters": {
        "iv": "base64-encoded-string",
        "aad": "base64-encoded-string"
    },
    "plaintext": "base64-encoded-string"
}
RSA-PKCS1
{
    "keyHandle": "string",
    "algorithm": "RSA-PKCS1",
    "plaintext": "base64-encoded-string"
}
RSA-NO-PADDING
{
    "keyHandle": "string",
    "algorithm": "RSA-NO-PADDING",
    "plaintext": "base64-encoded-string"
}

Response

{
    "ciphertext": "base64-encoded-string"
}

For AEAD encryption, the ciphertext includes the AEAD tag so the caller does not need to handle that specially.

Note also that the exact AEAD algorithm used cannot be chosen by the caller; it is up to the libaziot-keys implementation. The libaziot-keys shipped by Microsoft uses AES-GCM. It also encodes a version number in the ciphertext to identify the algorithm used, so that the algorithm can be modified in the future if necessary while still being able to decrypt ciphertext created with the old algorithm.


Decrypt

POST /decrypt?api-version=2021-05-01

Authentication

Not required.

Request

AEAD

Only valid for symmetric keys.

{
    "keyHandle": "string",
    "algorithm": "AEAD",
    "parameters": {
        "iv": "base64-encoded-string",
        "aad": "base64-encoded-string"
    },
    "ciphertext": "base64-encoded-string"
}

Response

{
    "plaintext": "base64-encoded-string"
}

The ciphertext must have come from the /encrypt API so that it matches the format that the /decrypt API expects. See the note in the /encrypt API above for details.

Note that the /decrypt API does not support the RSA-PKCS1 and RSA-NO-PADDING algorithms that /encrypt does. Decryption with those algorithms is done with the public key, which can be done by the caller without involving the Keys Service, since the caller has access to the public key via /parameters/


API authentication

APIs that create or retrieve keys require the caller to authenticate with KS. Allowed callers are listed in the KS config directory, /etc/aziot/keyd/config.d.

Each file in the KS config directory should list allowed Unix user IDs (UIDs) and the keys that those users may access. The file name does not matter, but files must have the extension .toml. Only files directly under the config directory are parsed (i.e. the config directory is not searched recursively).

For example, /etc/aziot/keyd/config.d/example.toml:

# Each user should be listed as a [[principal]]
# This principal grants user 1000 access to the 'example1' and 'example2' key.
[[principal]]
uid = 1000
keys = ["example1", "example2"]

# Wildcards may also be used for key IDs.
# This principal grants user 1001 access to all key IDs beginning with 'example'.
#
# Supported wildcards are:
#  * (placeholder for any characters)
#  ? (placeholder for a single character)
[[principal]]
uid = 1001
keys = ["example*"]

In addition, all users added as principals must be in the aziotks group.

Code organization

The KS is made up of the following crates: