diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..cfa4370189676c011d73d45d4111e383ea8f3b27
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+bin/
+vendor/
+Gopkg.lock
+
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 0000000000000000000000000000000000000000..6e4954b45287512568d441b89e2ef45c00efcee1
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,27 @@
+[[constraint]]
+  branch = "master"
+  name = "code.vereign.com/code/viam-apis"
+
+[[constraint]]
+  branch = "master"
+  name = "code.vereign.com/code/data-storage-agent"
+
+[[constraint]]
+  name = "github.com/golang/protobuf"
+  version = "1.1.0"
+
+[[constraint]]
+  name = "github.com/grpc-ecosystem/grpc-gateway"
+  version = "1.4.1"
+
+[[constraint]]
+  branch = "master"
+  name = "golang.org/x/net"
+
+[[constraint]]
+  name = "google.golang.org/grpc"
+  version = "1.13.0"
+
+[prune]
+  go-tests = true
+  unused-packages = true
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e84137fd9f75576cddc61728006ea28dc499862f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d95e1e5cec40a31c8f4fee3b276f5e0c0d439673
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+SERVER_OUT := "bin/server"
+PKG := "code.vereign.com/code/key-storage-agent"
+SERVER_PKG_BUILD := "${PKG}"
+PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/)
+
+.PHONY: all api server
+
+all: server
+
+dep: ## Get the dependencies
+	dep ensure -update
+server: dep ## Build the binary file for server
+	@go build -i -v -o $(SERVER_OUT) $(SERVER_PKG_BUILD)
+
+clean: ## Remove previous builds
+	@rm $(SERVER_OUT)
+
+help: ## Display this help screen
+	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
diff --git a/cert/server.crt b/cert/server.crt
new file mode 100644
index 0000000000000000000000000000000000000000..ffc52d260e9fac51405c58e02317690c9e79cfa2
--- /dev/null
+++ b/cert/server.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiYCCQDpx954xyvbgjANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJG
+UjEMMAoGA1UECAwDaWRmMQ4wDAYDVQQHDAVQYXJpczESMBAGA1UECgwJUGFudG9t
+YXRoMQwwCgYDVQQLDANub2MxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzEwMDUx
+NTI5MzZaFw0yNzEwMDMxNTI5MzZaMGExCzAJBgNVBAYTAkZSMQwwCgYDVQQIDANp
+ZGYxDjAMBgNVBAcMBVBhcmlzMRIwEAYDVQQKDAlQYW50b21hdGgxDDAKBgNVBAsM
+A25vYzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA9UFeeiJ5Gyi5MZGEI0ME8v4IikVByiBgwqn6PH/bYuJwRoR3acZg
+tiiMS1pyfUBSQ2iTLRzrkvFd5rXByXWK4+6MeqYdAzAyQzgk6/1U58oPzGrZCRYe
+b3Bm7QvS9rl00keO37gE8ETpatL8rCQt9Qsl88ah1BfCVuDdFtBdOW2Qz1i6qGUv
+pkTSJDZBmE3gjWGHIp4UjcdshFlTEjmFfcKtNJtMuhnKZIgo6KZcN1Trvyf4aUUM
+zQbPFm2jGd5lUFZJQvSQ00k+TF4YrbuDVfhozoxBrbsoaRXkVWVYC1fYey89FY1n
+9zFyxB6OF32EIry4Kn5Tu6AG9+9z/CU3gwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
+AQDUeByNiVS/XZgc4BXO5JPXY98orVZKfXEEWKzMfzPDxW925k2IpnnCpT4WkAe4
+sUR7C5efGPyv0TMTzNeXGrkB7lK/9WGWRrlR/bI0kdad7/p7Qx+5hC/nE2HWZYQo
+5JYj8tEfetY3aV64rFllcq2hfI71dMML05GwoVaKaMc9Q1ccwIZAbkXR2Sifwsn9
++UNNsP5hR+7kQh+Dqd/+qEySp1+0ZJ1LmRmRes37MlJI9KSoC1uANwcB5+4ZFrba
+LHrkszk9nxk09Y/tLGYlvvf23y1BdhcqT2EbUZX7jD/jEDC0kZ5yxDE1UDk+pnZp
+UaEcVsgg/b9dMESt38f6ICK/
+-----END CERTIFICATE-----
diff --git a/cert/server.csr b/cert/server.csr
new file mode 100644
index 0000000000000000000000000000000000000000..5662bf115417fa8cc05a5c987aa46e4bfbb229dd
--- /dev/null
+++ b/cert/server.csr
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICpjCCAY4CAQAwYTELMAkGA1UEBhMCRlIxDDAKBgNVBAgMA2lkZjEOMAwGA1UE
+BwwFUGFyaXMxEjAQBgNVBAoMCVBhbnRvbWF0aDEMMAoGA1UECwwDbm9jMRIwEAYD
+VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD1
+QV56InkbKLkxkYQjQwTy/giKRUHKIGDCqfo8f9ti4nBGhHdpxmC2KIxLWnJ9QFJD
+aJMtHOuS8V3mtcHJdYrj7ox6ph0DMDJDOCTr/VTnyg/MatkJFh5vcGbtC9L2uXTS
+R47fuATwROlq0vysJC31CyXzxqHUF8JW4N0W0F05bZDPWLqoZS+mRNIkNkGYTeCN
+YYcinhSNx2yEWVMSOYV9wq00m0y6GcpkiCjoplw3VOu/J/hpRQzNBs8WbaMZ3mVQ
+VklC9JDTST5MXhitu4NV+GjOjEGtuyhpFeRVZVgLV9h7Lz0VjWf3MXLEHo4XfYQi
+vLgqflO7oAb373P8JTeDAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAES8c7EOs
+rU0eu3whtUumllhotNvvqBP4x46arQQE2ud0GkLkxvxqbUuGQxLWi5KCcdads+Cx
+EramC/UAUgAFFj8Ll1EuSZxy1+sb5GL00uJMxatpDBHwr78fhllAWkM7jiZbh2ad
+FHOg9kQcDtdfFB6XP7JM7uiXluEQRyxIutoOzIkhZZva6zg/7iWE+u6DGz3r8dWQ
+WNH8gsWA3D85ZyTDVrCvp6omGx35pzwuQOoWH6nO3dCsR2smf58ShnMtE+c6uLbF
+qoZRTXGAiCaH3/Cn3TXkcrclZdneCCOWidHG2ICTsTqfujDYz/CCYM23AGkqQb1Y
+QMQl0LGZ+k+HAQ==
+-----END CERTIFICATE REQUEST-----
diff --git a/cert/server.key b/cert/server.key
new file mode 100644
index 0000000000000000000000000000000000000000..e4633619d4877c9d199a723e3334cf887dece536
--- /dev/null
+++ b/cert/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpgIBAAKCAQEA9UFeeiJ5Gyi5MZGEI0ME8v4IikVByiBgwqn6PH/bYuJwRoR3
+acZgtiiMS1pyfUBSQ2iTLRzrkvFd5rXByXWK4+6MeqYdAzAyQzgk6/1U58oPzGrZ
+CRYeb3Bm7QvS9rl00keO37gE8ETpatL8rCQt9Qsl88ah1BfCVuDdFtBdOW2Qz1i6
+qGUvpkTSJDZBmE3gjWGHIp4UjcdshFlTEjmFfcKtNJtMuhnKZIgo6KZcN1Trvyf4
+aUUMzQbPFm2jGd5lUFZJQvSQ00k+TF4YrbuDVfhozoxBrbsoaRXkVWVYC1fYey89
+FY1n9zFyxB6OF32EIry4Kn5Tu6AG9+9z/CU3gwIDAQABAoIBAQDcQdXAaD9NRdh0
+DNSX+nNyavRugV5hUYy0poTmWolDmEru+b5oj1GBpo7Aib0ygVaf1UYACO4D7KLB
+NNCRxe9zXmRpLc/2cg1h0wVNrxjWheCEXB0IjQXOXSsCjlDrZYjl5IAKqTA+PBVI
+660iR+fCHz35XZUubhwJfC7yczSWAe8nlnFHrcUzSeqLctI18JGsq3hDf5Fy+97+
+4uuJFPwQ0mLsgOdzKvCB79ecSZdQ18hkidgpnARaM1sI501b1Tp/uUQOLUmdVnvh
+/MFEWndm1th3i+gMotsBwrBCyPPeWVrcvKI2sf0LJmgaMl4/sBB0UsSKLhcbBLsj
+jvABikmJAoGBAP1z/WeNDaEaypXBSOKZlMu9YuPOemS2DY5GEc204Fi0dYNDlMEh
+CAu7mEsEvH66hwKn+xMnpb5hIuxQv3/2hUFTME9au2htj2MX0+qk1bqMQMlDEdda
+WWybxy+jW1mYJFMVHFwAAE7hXS5peH9ZCihAu/szYt8zPdZ4X3EEEqqfAoGBAPe4
+Slp2GVd742ZA3VBpfv6802C/DA98gIdHqWNF5vJzi1HU29m+2zY6mMGl9CP3ICeX
+gLL6a3bqIc8aPgJ8ULAhegKOcFqruhGFIjmd+FPRtwjiYC9jJRXbMUSmTrR0XsxG
+GkK2UmBNxVNGUj++1hwji39OfsMnf6OvfVhnmOydAoGBAJk5OgUUHR08WSTXyPxU
+5MOXJuWZuhyQgvl0GudFZiu6TSCiBpgLJBYTvyn7HwluMpjEfOFDosvJZZd/6YWu
+vziS1i3jKFEliv3ZNeAw7pTsnW4PAgYzNMSYGH8QPvWXKL6hkJd92LHXRMH+OT6j
+0aQsHnjqw+czzzqNYwWr9Kz5AoGBAKvxBeLuUD6x5jAGW9dBsn08MXfYg5WINGox
+qngWf+vPmWdOWN81o1BrsbXP67q/AFmaxiD0wnzCnH701w/Am/z074wws/mrcrZQ
+c2YMqN39FY+cGWkq5wXZo8Pjr4N/toERM48Un+7qbEmV6OcIHfNgFKZjpIbutqC1
+4UnodnPdAoGBANzcLKz99NXBBuAiYHgmOckh6I2RCcORgE6WDbj57qrdMco0NToU
+wU9ute0SBEm6VEnBf9i3jlrPZr69f3VT4OFWeo9RoHkVmVDD+LEY5P7xqftj/XZy
+2r+uvgkqZWBC3rpAORGq3F7MgD4nFcyssFKwylEGyCVCfyGIsv5+ZKMr
+-----END RSA PRIVATE KEY-----
diff --git a/cert/vereign_ca.cer b/cert/vereign_ca.cer
new file mode 100644
index 0000000000000000000000000000000000000000..6aacfac5ee9a0c352d35ebc86d9e3a4ee848841d
--- /dev/null
+++ b/cert/vereign_ca.cer
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEnjCCA4agAwIBAgIEW2lRSjANBgkqhkiG9w0BAQsFADCBoTETMBEGCgmSJomT
+8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB3ZlcmVpZ24xCzAJBgNVBAYTAkJH
+MRAwDgYDVQQIDAdQbG92ZGl2MRAwDgYDVQQHDAdQbG92ZGl2MRMwEQYDVQQKDApW
+ZXJlaWduIEFHMRUwEwYDVQQLDAxWZXJlaWduIExhYnMxFDASBgNVBAMMC3ZlcmVp
+Z24uY29tMB4XDTE4MDgwNzA3NTkwNloXDTI4MDgwNzA3NTkwNlowgaExEzARBgoJ
+kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgd2ZXJlaWduMQswCQYDVQQG
+EwJCRzEQMA4GA1UECAwHUGxvdmRpdjEQMA4GA1UEBwwHUGxvdmRpdjETMBEGA1UE
+CgwKVmVyZWlnbiBBRzEVMBMGA1UECwwMVmVyZWlnbiBMYWJzMRQwEgYDVQQDDAt2
+ZXJlaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYs0VOg
+HyXuNbJhYjZBLKoR2EH95VYQ5BStX+KD7ppxlT+H4sxbuj11xVVcDj95aJvlc9Nc
+yBdWktjkIi+MrqoiMM1ljuCzwSsvfnVidWGhZmqSNvEjXgAkX57NoG0U+C9AK16i
+otLApBQ79sXSONfxq2fbdXlaGm98ahCLreomFqKXizkTsOmnirbouJvTX0eFXeaA
++qXPhGpsQxu7vOlWoWqgCAqPAn2krpIBKPvX8n9rL29tFs8JXft0Z5MKykCweP8D
+Sn3e4nmMUDRl8F/0+r+1HIK5FWw2vKUrinMAN/YkpsfEE/flIlZCKg3D8GEYnMFQ
+w9Gaz7NVH87qI8sCAwEAAaOB2zCB2DAeBgNVHREEFzAVgRNjb250YWN0QHZlcmVp
+Z24uY29tMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MIGaBgNVHSUEgZIwgY8G
+CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCisGAQQBgjcKAwwGCSqGSIb3
+LwEBBQYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCCsGAQUFBwMFBggrBgEFBQcDBgYI
+KwYBBQUHAwcGCCsGAQUFBwMIBggrBgEFBQcDCQYKKwYBBAGCNxQCAgYEVR0lADAN
+BgkqhkiG9w0BAQsFAAOCAQEAMotIWeKzq8T2CZR6hzUMVjBzLfJRnKKXLwoaa3R0
+mXwOcyloQmIQkYqQ7M4ELDEmAtN/f7cE/uBhUdD8UEWn0I4Im6Al8Q7eUFPOAvW3
+uvoqEx5+0sMjsBDUxVW1xkcwYIP9Vpp7occ4Uu0dbj6WR6jsTWQFor+Fc+J4wkRq
+5a4i7pnI78r41rJAHpIUqToLmcoxBOqVrjDys/scCQcxlDGgZcy7T4OFGgJGUdY0
+Zs2W/7GdZUKctb4d+2kWwvA+34w8V9lOBTwM2ddSYS/EkUYMkP93Cb0/LH9Go43u
+U2lEx/41yecR4bipRcwHamTOlvpsFoC9+NjZ0m+l9EM0vA==
+-----END CERTIFICATE-----
diff --git a/cert/vereign_ca.key b/cert/vereign_ca.key
new file mode 100644
index 0000000000000000000000000000000000000000..2bdd81dff19a2917475fa8845923b4021ce475f3
--- /dev/null
+++ b/cert/vereign_ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2LNFToB8l7jWy
+YWI2QSyqEdhB/eVWEOQUrV/ig+6acZU/h+LMW7o9dcVVXA4/eWib5XPTXMgXVpLY
+5CIvjK6qIjDNZY7gs8ErL351YnVhoWZqkjbxI14AJF+ezaBtFPgvQCteoqLSwKQU
+O/bF0jjX8atn23V5WhpvfGoQi63qJhail4s5E7Dpp4q26Lib019HhV3mgPqlz4Rq
+bEMbu7zpVqFqoAgKjwJ9pK6SASj71/J/ay9vbRbPCV37dGeTCspAsHj/A0p93uJ5
+jFA0ZfBf9Pq/tRyCuRVsNrylK4pzADf2JKbHxBP35SJWQioNw/BhGJzBUMPRms+z
+VR/O6iPLAgMBAAECggEAG9HMRZD2MLynxo3IibB6OZ5v/+Pd2b7Klb3EHrs2/K7L
+s9/0anC3iBsr/1UHd/n6V5Q6k9RfWfEGi8iKz+gT5DdEbJlNsFLC9O1Tymk2s6oK
+EcwyR7C28h6b24xbK01AeTa7aMA9TSHN7KkbjioENDXbjwicb+OqlcvSBqTN8iuM
+aZrpLHG1ddd7qceUsJuZWkrtC8/RIv/OOPbjdCx2US24T1AgpSANgReHWqk2C8aK
+Bo/Np2NhKKr0lmWN7mhXKBV/OVtM8QPFd8JfsI4vQByd3aV0R5GJpBgX/sP2rQi5
+CnZSV45f6OrYNbzK3DgNdVLFqFUdvAdyroyClTDQgQKBgQDzm6WnmjKg20wUi3tb
+Wy7syU8Ss4WBFeCjt5aVkqeILgdeMwy+FBnXZNfU5enNBTjPMRcAfPuVm0jet79H
+NLgHrTU80sb5fQ0fENlS031OOdEG0PjeoCCGfGsf/YFsmS2WYSHlkYlbibItCmzn
+WTVmu0KIQ3H82YDqz7vu/NQ0WQKBgQC/cSsdwPrMVT1XcSANB77/81v2t3ZVrckx
+gp1KNWKEmaVgWfFsNQ780d4HQAdhKAa9eKRLAL3R7hIDOGXSTPkxEZ95LwkzbNlf
+qSnlxTwhRY41+OHYdjHMzCTu8qoumwPLCrFkKBdU/s5z84HA8KU1nAIAJzz1mNAN
+qbT+Bv/kwwKBgCTSV/23bwOlYiCQ3Lp4U+VyoEMhY4KZffUBIP/GxQ/udSql6L0q
+aKWIFp+ViPt2WJnov6NRQO3iJOeVOpJWw6JVagChk3XOkxcpAtBkK0KRtqijGZr8
+9S2ezMpvFQsHND7Qu8DpeKufapEoTEHD2DCJCYtzNl2TusrDT5LWIHUxAoGADCwe
+6LJnf+x/jPrFZe6zJ0UK+OHrZUE6hKpgY+KHFBVM3ZZ6cj3haRPTATUCAxxvaUat
+c5Nlfl6byJaiar+4LHWJZUQnWpy2KY3w+woSa68nfqkHeyLwwavNQWAuj+4NTLCu
+XMbrzNyytc6q1mC2sHTt76KPDrKbr/K1bl11kc8CgYEAodKJD6bP4w1vWDR08/HU
+T4I0XaKq5X150BbwQZO0axEsuiVwqsosioXYSVAW85NOWSTNDSgpVPCjyWRyHyRL
+cVVrWMQda3Hc/s6EzsiqC0BGw9D0r3TZN8n7Wm+BoNkek//xPhoiLfNTKtwRZIcr
+CikzGE28ynzRwrDK70wV7Q4=
+-----END PRIVATE KEY-----
diff --git a/handler/generate_certificate.go b/handler/generate_certificate.go
new file mode 100644
index 0000000000000000000000000000000000000000..07caca54c709261075ae497db352e848c7c74f95
--- /dev/null
+++ b/handler/generate_certificate.go
@@ -0,0 +1,215 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package handler
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"io/ioutil"
+	"math/big"
+	"time"
+
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	"code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"code.vereign.com/code/viam-apis/utils"
+	"code.vereign.com/code/viam-apis/versions"
+	"github.com/golang/protobuf/proto"
+	"golang.org/x/net/context"
+)
+
+func (s *KeyStorageServerImpl) GenerateCertificate(ctx context.Context, in *api.GenerateCertificateRequest) (*api.GenerateCertificateResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	generateCertificateResponse := &api.GenerateCertificateResponse{}
+
+	aesKeyBytes, err := rsaDecryptWithServerKey(s.VereignPrivateKeyFilePath, in.EncryptedAesKey, []byte("aeskeys"))
+	if err != nil {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, err.Error())
+		return generateCertificateResponse, nil
+	}
+
+	// Get and decrypt rsa private key
+	encryptedPrivateKeyMessage := &api.Key{}
+	data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE))
+	if data.Errors != "" {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, data.Errors)
+		return generateCertificateResponse, nil
+	}
+	proto.Unmarshal(data.Data.Data, encryptedPrivateKeyMessage)
+
+	privateKeyBytes, err := aesDecrypt(aesKeyBytes, in.PrivateKeyNonce, encryptedPrivateKeyMessage.Content)
+	if err != nil {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, err.Error())
+		return generateCertificateResponse, nil
+	}
+
+	// Get and decrypt rsa public key
+	encryptedPublicKeyMessage := &api.Key{}
+	data, _ = client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC))
+	if data.Errors != "" {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, data.Errors)
+		return generateCertificateResponse, nil
+	}
+	proto.Unmarshal(data.Data.Data, encryptedPublicKeyMessage)
+
+	publicKeyBytes, err := aesDecrypt(aesKeyBytes, in.PublicKeyNonce, encryptedPublicKeyMessage.Content)
+	if err != nil {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, err.Error())
+		return generateCertificateResponse, nil
+	}
+
+	certificateBytes, err := generateCertificate(privateKeyBytes, publicKeyBytes, s.VereignCertFilePath, in.CertificateData)
+	if err != nil {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"400", api.StatusType_ERROR, err.Error())
+		return generateCertificateResponse, nil
+	}
+
+	certificateMessage := &api.Key{
+		Content: certificateBytes,
+	}
+
+	result, errors, err := client.DoPutDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), certificateMessage, versions.EntitiesManagementAgentApiVersion)
+	generateCertificateResponse.StatusList = handlePutDataErrors(generateCertificateResponse.StatusList, errors, err)
+
+	if generateCertificateResponse.StatusList == nil || len(generateCertificateResponse.StatusList) == 0 {
+		generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList,
+			"200", api.StatusType_INFO, result)
+	}
+
+	return generateCertificateResponse, nil
+}
+
+func generateCertificate(privateKeyBytes []byte, publicKeyBytes []byte, caCertFilePath string,
+	certificateData *api.GenerateCertificateRequest_CertificateData) ([]byte, error) {
+
+	privateKey, err := x509.ParsePKCS8PrivateKey(privateKeyBytes)
+	if err != nil {
+		return nil, err
+	}
+	publicKey, err := x509.ParsePKIXPublicKey(publicKeyBytes)
+	if err != nil {
+		return nil, err
+	}
+
+	notBeforeTime := time.Unix(certificateData.NotBefore.Seconds, int64(certificateData.NotBefore.Nanos)).UTC()
+	notAfterTime := time.Unix(certificateData.NotAfter.Seconds, int64(certificateData.NotAfter.Nanos)).UTC()
+
+	template := x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject: pkix.Name{
+			Country:            []string{certificateData.Country},
+			Organization:       []string{certificateData.Organization},
+			OrganizationalUnit: []string{certificateData.OrganizationalUnit},
+			CommonName:         certificateData.CommonName,
+		},
+		NotBefore:             notBeforeTime,
+		NotAfter:              notAfterTime,
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+		IsCA:     false,
+		DNSNames: []string{certificateData.Host},
+	}
+
+	caCertificate, err := readCertificateFromFile(caCertFilePath)
+	if err != nil {
+		return nil, err
+	}
+
+	certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, caCertificate, publicKey, privateKey)
+	if err != nil {
+		return nil, err
+	}
+
+	return certificateBytes, nil
+}
+
+func readPrivateKeyFromFile(fileName string) (*rsa.PrivateKey, error) {
+	privateKeyPemBlock, err := readPemBlockFromFile(fileName)
+	if err != nil {
+		return nil, err
+	}
+
+	parseResult, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	privateKey := parseResult.(*rsa.PrivateKey)
+
+	return privateKey, nil
+}
+
+func readPemBlockFromFile(fileName string) (*pem.Block, error) {
+	fileBytes, err := ioutil.ReadFile(fileName)
+	if err != nil {
+		return nil, err
+	}
+
+	certificatePemBlock, _ := pem.Decode(fileBytes)
+
+	return certificatePemBlock, nil
+}
+
+func rsaDecryptWithServerKey(privateKeyFilePath string, encryptedMessage []byte, label []byte) ([]byte, error) {
+	serverPrivateKey, err := readPrivateKeyFromFile(privateKeyFilePath)
+	if err != nil {
+		return nil, err
+	}
+
+	message, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, serverPrivateKey, encryptedMessage, label)
+	if err != nil {
+		return nil, err
+	}
+
+	return message, nil
+}
+
+func aesDecrypt(aesKey []byte, nonce []byte, encryptedMessage []byte) ([]byte, error) {
+	block, err := aes.NewCipher(aesKey)
+	if err != nil {
+		return nil, err
+	}
+
+	aesgcm, err := cipher.NewGCM(block)
+	if err != nil {
+		return nil, err
+	}
+
+	message, err := aesgcm.Open(nil, nonce, encryptedMessage, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return message, nil
+}
diff --git a/handler/generate_keypair.go b/handler/generate_keypair.go
new file mode 100644
index 0000000000000000000000000000000000000000..0b106cd0e7c58d9b59b82a9b8fcb1709b26ddf5e
--- /dev/null
+++ b/handler/generate_keypair.go
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package handler
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	"code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"code.vereign.com/code/viam-apis/utils"
+	"code.vereign.com/code/viam-apis/versions"
+	"golang.org/x/net/context"
+)
+
+func (s *KeyStorageServerImpl) GenerateKeyPair(ctx context.Context, in *api.GenerateKeyPairRequest) (*api.GenerateKeyPairResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	generateKeyPairResponse := &api.GenerateKeyPairResponse{}
+
+	uuid, err := generateUnusedUUID(client)
+	if err != nil {
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"500", api.StatusType_ERROR, err.Error())
+	}
+
+	privateKeyBytes, publicKeyBytes, err := generateKeyPair(int(in.KeySize))
+	if err != nil {
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"500", api.StatusType_ERROR, err.Error())
+	}
+
+	aesKeyBytes, err := generateRandomSequence(256)
+	if err != nil {
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"500", api.StatusType_ERROR, err.Error())
+	}
+
+	encryptedPrivateKeyBytes, privateKeyNonce, err := aesEncrypt(aesKeyBytes, privateKeyBytes)
+	if err != nil {
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"500", api.StatusType_ERROR, err.Error())
+		return generateKeyPairResponse, nil
+	}
+	encryptedPrivateKey := &api.Key{Content: encryptedPrivateKeyBytes}
+	result, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), encryptedPrivateKey, versions.EntitiesManagementAgentApiVersion)
+	generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)
+
+	publicKeyNonce := []byte{}
+	if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
+		encryptedPublicKeyBytes, publicKeyNonceLocal, err := aesEncrypt(aesKeyBytes, publicKeyBytes)
+		publicKeyNonce = publicKeyNonceLocal
+		if err != nil {
+			generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+				"500", api.StatusType_ERROR, err.Error())
+			return generateKeyPairResponse, nil
+		}
+		encryptedPublicKey := &api.Key{Content: encryptedPublicKeyBytes}
+		result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), encryptedPublicKey, versions.EntitiesManagementAgentApiVersion)
+		generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)
+	}
+
+	encryptedAesKeyBytes, err := rsaEncryptWithServerKey(s.VereignCertFilePath, aesKeyBytes, []byte("aeskeys"))
+	if err != nil {
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"500", api.StatusType_ERROR, err.Error())
+		return generateKeyPairResponse, nil
+	}
+
+	if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
+		generateKeyPairResponse.Uuid = uuid
+		generateKeyPairResponse.EncryptedAesKey = encryptedAesKeyBytes
+		generateKeyPairResponse.PrivateKeyNonce = privateKeyNonce
+		generateKeyPairResponse.PublicKeyNonce = publicKeyNonce
+		generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
+			"200", api.StatusType_INFO, result)
+	}
+
+	return generateKeyPairResponse, nil
+}
+
+func generateKeyPair(keySize int) ([]byte, []byte, error) {
+	privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	err = privateKey.Validate()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	publicKey := &privateKey.PublicKey
+
+	privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
+	if err != nil {
+		return nil, nil, err
+	}
+	publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return privateKeyBytes, publicKeyBytes, nil
+}
+
+func rsaEncryptWithServerKey(certFilePath string, message []byte, label []byte) ([]byte, error) {
+	serverCertificate, err := readCertificateFromFile(certFilePath)
+	if err != nil {
+		return nil, err
+	}
+	serverPublicKey := serverCertificate.PublicKey.(*rsa.PublicKey)
+
+	encryptedMessageBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, serverPublicKey, message, label)
+	if err != nil {
+		return nil, err
+	}
+
+	return encryptedMessageBytes, nil
+}
+
+func aesEncrypt(aesKey []byte, message []byte) ([]byte, []byte, error) {
+	block, err := aes.NewCipher(aesKey)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	aesgcm, err := cipher.NewGCM(block)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	nonce, err := generateRandomSequence(aesgcm.NonceSize() * 8)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	encryptedMessage := aesgcm.Seal(nil, nonce, message, nil)
+
+	return encryptedMessage, nonce, nil
+}
+
+func generateRandomSequence(keySize int) ([]byte, error) {
+	key := make([]byte, keySize/8)
+
+	_, err := rand.Read(key)
+	if err != nil {
+		return nil, err
+	}
+
+	return key, nil
+}
diff --git a/handler/handler.go b/handler/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..293a3408d8ed1346e9a112df4d0d895f0cce61aa
--- /dev/null
+++ b/handler/handler.go
@@ -0,0 +1,167 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package handler
+
+import (
+	"strings"
+
+	"code.vereign.com/code/viam-apis/versions"
+	"github.com/golang/protobuf/proto"
+
+	"code.vereign.com/code/viam-apis/authentication"
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	"code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"code.vereign.com/code/viam-apis/utils"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc/metadata"
+)
+
+// Server represents the gRPC server
+type KeyStorageServerImpl struct {
+	DataStorageUrl            string
+	CertFilePath              string
+	VereignCertFilePath       string
+	VereignPrivateKeyFilePath string
+}
+
+func (s *KeyStorageServerImpl) CreateAuthentication(ctx context.Context) *authentication.Authentication {
+	if md, ok := metadata.FromIncomingContext(ctx); ok {
+		uuid := strings.Join(md["uuid"], "")
+		session := strings.Join(md["session"], "")
+
+		auth := &authentication.Authentication{
+			Uuid:    uuid,
+			Session: session,
+		}
+
+		return auth
+	}
+
+	return nil
+}
+
+func (s *KeyStorageServerImpl) GetKey(ctx context.Context, in *api.GetKeyRequest) (*api.GetKeyResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	getKeyResponse := &api.GetKeyResponse{}
+
+	if in.KeyType == api.KeyType_KT_EMPTY {
+		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
+			"400", api.StatusType_ERROR, "KeyType cannot be empty")
+	}
+
+	data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
+
+	if data.Errors != "" {
+		getKeyResponse.Key = nil
+		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
+			"500", api.StatusType_ERROR, data.Errors)
+	} else {
+		key := &api.Key{}
+		proto.Unmarshal(data.Data.Data, key)
+		getKeyResponse.Key = key
+	}
+
+	return getKeyResponse, nil
+}
+
+func (s *KeyStorageServerImpl) SetKey(ctx context.Context, in *api.SetKeyRequest) (*api.SetKeyResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	setKeyResponse := &api.SetKeyResponse{}
+
+	if in.KeyType == api.KeyType_KT_EMPTY {
+		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
+			"400", api.StatusType_ERROR, "KeyType cannot be empty")
+	}
+
+	data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
+
+	if data.Errors != "" {
+		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
+			"400", api.StatusType_ERROR, data.Errors)
+		return setKeyResponse, nil
+	}
+
+	key := &api.Key{}
+	proto.Unmarshal(data.Data.Data, key)
+	if key != nil && key.Content != nil && len(key.Content) > 0 {
+		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
+			"400", api.StatusType_ERROR, "Key is already set")
+		return setKeyResponse, nil
+	}
+
+	result, errors, err := client.DoPutDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), in.Key, versions.EntitiesManagementAgentApiVersion)
+	setKeyResponse.StatusList = handlePutDataErrors(setKeyResponse.StatusList, errors, err)
+
+	if setKeyResponse.StatusList == nil || len(setKeyResponse.StatusList) == 0 {
+		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
+			"200", api.StatusType_INFO, result)
+	}
+
+	return setKeyResponse, nil
+}
+
+func (s *KeyStorageServerImpl) ReserveKeyUUID(ctx context.Context, in *api.ReserveKeyUUIDRequest) (*api.ReserveKeyUUIDResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	reserveKeyUUIDResponse := &api.ReserveKeyUUIDResponse{}
+
+	uuid, err := generateUnusedUUID(client)
+	if err != nil {
+		reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList,
+			"500", api.StatusType_INFO, err.Error())
+	}
+
+	emptyKey := &api.Key{
+		Content: []byte{},
+	}
+
+	result, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
+	reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
+
+	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
+		result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), emptyKey, versions.EntitiesManagementAgentApiVersion)
+		reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
+	}
+
+	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
+		result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
+		reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
+	}
+
+	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
+		reserveKeyUUIDResponse.Uuid = uuid
+		reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList,
+			"200", api.StatusType_INFO, result)
+	}
+
+	return reserveKeyUUIDResponse, nil
+}
diff --git a/handler/revoke.go b/handler/revoke.go
new file mode 100644
index 0000000000000000000000000000000000000000..2b779ed3372b1ef99fa2ba7d12823a8596386d84
--- /dev/null
+++ b/handler/revoke.go
@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package handler
+
+import (
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	"code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"code.vereign.com/code/viam-apis/utils"
+	"code.vereign.com/code/viam-apis/versions"
+	"github.com/golang/protobuf/proto"
+	"golang.org/x/net/context"
+)
+
+func (s *KeyStorageServerImpl) Revoke(ctx context.Context, in *api.RevokeRequest) (*api.RevokeResponse, error) {
+	auth := s.CreateAuthentication(ctx)
+
+	client := &client.DataStorageClientImpl{}
+	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
+	defer client.CloseClient()
+
+	revokeResponse := &api.RevokeResponse{}
+
+	revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_PRIVATE)
+	if revokeResponse.StatusList != nil {
+		return revokeResponse, nil
+	}
+
+	revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_PUBLIC)
+	if revokeResponse.StatusList != nil {
+		return revokeResponse, nil
+	}
+
+	revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_CERTIFICATE)
+	if revokeResponse.StatusList != nil {
+		return revokeResponse, nil
+	}
+
+	revokeResponse.StatusList = utils.AddStatus(revokeResponse.StatusList, "200", api.StatusType_INFO, "Keys revoked")
+	return revokeResponse, nil
+}
+
+func revokeKey(client *client.DataStorageClientImpl, uuid string, keyType api.KeyType) []*api.Status {
+
+	statusList := []*api.Status{}
+
+	data, _ := client.DoGetDataCall("keys", uuid+"/"+api.KeyType.String(keyType))
+	if data.Errors != "" {
+		statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, data.Errors)
+		return statusList
+	}
+
+	key := &api.Key{}
+	proto.Unmarshal(data.Data.Data, key)
+
+	key.Revoked = true
+
+	_, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(keyType), key, versions.EntitiesManagementAgentApiVersion)
+	statusList = handlePutDataErrors(statusList, errors, err)
+	if statusList != nil && len(statusList) > 0 {
+		return statusList
+	}
+
+	return nil
+}
diff --git a/handler/utils.go b/handler/utils.go
new file mode 100644
index 0000000000000000000000000000000000000000..a489edca30ce359b8bf3431d6faced0b2797c520
--- /dev/null
+++ b/handler/utils.go
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package handler
+
+import (
+	"crypto/rand"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	"code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"code.vereign.com/code/viam-apis/utils"
+)
+
+func generateUnusedUUID(client *client.DataStorageClientImpl) (string, error) {
+	count := 0
+	for {
+		uuid, err := newUUID()
+
+		// check that uuid is not used
+		data, _ := client.DoGetDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE))
+
+		if data.Errors != "" || err != nil {
+			return uuid, nil
+		}
+		if count >= 10 {
+			return "", errors.New("Could not generate unused UUID in 10 tries")
+		}
+		count++
+	}
+}
+
+func newUUID() (string, error) {
+	uuid := make([]byte, 16)
+	n, err := io.ReadFull(rand.Reader, uuid)
+	if n != len(uuid) || err != nil {
+		return "", err
+	}
+
+	uuid[8] = uuid[8]&^0xc0 | 0x80
+	uuid[6] = uuid[6]&^0xf0 | 0x40
+
+	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
+}
+
+func handlePutDataErrors(statusList []*api.Status, errors string, err error) []*api.Status {
+	if err != nil {
+		statusList = utils.AddStatus(statusList, "500", api.StatusType_ERROR, err.Error())
+	} else if errors != "" {
+		statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, errors)
+	}
+
+	return statusList
+}
+
+func readCertificateFromFile(fileName string) (*x509.Certificate, error) {
+	certificatePemBlock, err := readPemBlockFromFile(fileName)
+	if err != nil {
+		return nil, err
+	}
+
+	certificate, err := x509.ParseCertificate(certificatePemBlock.Bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	return certificate, nil
+}
diff --git a/kill.sh b/kill.sh
new file mode 100755
index 0000000000000000000000000000000000000000..40d73ddc80314f22e053c5dd8353dc5c8b233579
--- /dev/null
+++ b/kill.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+PIDFILE="$HOME/tmp/key-storage-agent.pid"
+kill -9 `cat $PIDFILE`
diff --git a/main.go b/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ed788dfa721c3818628fccaee0d525e01a7c1b3
--- /dev/null
+++ b/main.go
@@ -0,0 +1,67 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"code.vereign.com/code/key-storage-agent/server"
+	"code.vereign.com/code/viam-apis/utils"
+)
+
+// main start a gRPC server and waits for connection
+func main() {
+
+	// TODO this should be done via configuration or even a certificate repository
+	certDir := utils.GetCertDirFromFlags()
+	if certDir == "" {
+		log.Printf("cert-dir cannot be empty")
+		return
+	}
+
+	grpcAddress := fmt.Sprintf("%s:%d", "localhost", 7877)
+	restAddress := fmt.Sprintf("%s:%d", "localhost", 7878)
+	dataStorageAddress := fmt.Sprintf("%s:%d", "localhost", 7777)
+
+	certFilePath := certDir + "/server.crt"
+	privateKeyFilePath := certDir + "/server.key"
+	vereignCertFilePath := certDir + "/vereign_ca.cer"
+	vereignPrivateKeyFilePath := certDir + "/vereign_ca.key"
+
+	// fire the gRPC server in a goroutine
+	go func() {
+		err := server.StartGRPCServer(grpcAddress, certFilePath, privateKeyFilePath, vereignCertFilePath,
+			vereignPrivateKeyFilePath, dataStorageAddress)
+		if err != nil {
+			log.Fatalf("failed to start gRPC server: %s", err)
+		}
+	}()
+
+	// fire the REST server in a goroutine
+	go func() {
+		err := server.StartRESTServer(restAddress, grpcAddress, certFilePath)
+		if err != nil {
+			log.Fatalf("failed to start gRPC server: %s", err)
+		}
+	}()
+
+	// infinite loop
+	log.Printf("Entering infinite loop")
+	select {}
+}
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ddfaeae8a956962a9c11ff73a110f88f18893a07
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+mkdir -p "$HOME/tmp"
+PIDFILE="$HOME/tmp/key-storage-agent.pid"
+
+if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= |
+                           grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then
+  echo "Already running."
+  exit 99
+fi
+
+PATH=$PATH:/usr/local/bin
+
+nohup $GOPATH/src/code.vereign.com/code/key-storage-agent/bin/server --cert-dir $GOPATH/src/code.vereign.com/code/key-storage-agent/cert > $HOME/key-storage-agent.log 2>&1 &
+
+echo $! > "${PIDFILE}"
+chmod 644 "${PIDFILE}"
diff --git a/server/server.go b/server/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..40e6a427ae6e7f8f8a88598daba917a20cf12029
--- /dev/null
+++ b/server/server.go
@@ -0,0 +1,176 @@
+package server
+
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import (
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"strings"
+
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+
+	"golang.org/x/net/context"
+
+	"code.vereign.com/code/key-storage-agent/handler"
+	"code.vereign.com/code/key-storage-agent/session"
+	"code.vereign.com/code/viam-apis/authentication"
+	"code.vereign.com/code/viam-apis/data-storage-agent/client"
+	api "code.vereign.com/code/viam-apis/key-storage-agent/api"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"google.golang.org/grpc/metadata"
+)
+
+// private type for Context keys
+type contextKey int
+
+const (
+	clientIDKey contextKey = iota
+)
+
+var pkgCertFile string
+
+func credMatcher(headerName string) (mdName string, ok bool) {
+	if headerName == "Session" {
+		return headerName, true
+	}
+	return "", false
+}
+
+// authenticateAgent check the client credentials
+func authenticateClient(ctx context.Context, s *handler.KeyStorageServerImpl, invokedMethod string) (string, error) {
+	if md, ok := metadata.FromIncomingContext(ctx); ok {
+
+		clientAuth := &authentication.Authentication{
+			Uuid:    strings.Join(md["uuid"], ""),
+			Session: strings.Join(md["session"], ""),
+		}
+
+		viamAuth := &authentication.Authentication{
+			Uuid:    "viam-system",
+			Session: "viam-session",
+		}
+
+		sessionClient := &client.DataStorageClientImpl{}
+		sessionClient.SetUpClient(viamAuth, "localhost:7777", pkgCertFile)
+		defer sessionClient.CloseClient()
+
+		if clientAuth.Uuid == viamAuth.Uuid {
+			if clientAuth.Session != viamAuth.Session {
+				return "", fmt.Errorf("bad session %s", clientAuth.Session)
+			}
+		} else {
+			if session.CheckSession(clientAuth.Uuid, clientAuth.Session, sessionClient) == false {
+				return "", fmt.Errorf("bad session %s", clientAuth.Session)
+			}
+		}
+
+		log.Printf("authenticated uuid: %s", clientAuth.Uuid)
+
+		return clientAuth.Uuid, nil
+	}
+	return "", fmt.Errorf("missing credentials")
+}
+
+// unaryInterceptor call authenticateClient with current context
+func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler1 grpc.UnaryHandler) (interface{}, error) {
+	s, ok := info.Server.(*handler.KeyStorageServerImpl)
+	fmt.Println("Invoked method: " + info.FullMethod)
+	if !ok {
+		return nil, fmt.Errorf("unable to cast server")
+	}
+	clientID, err := authenticateClient(ctx, s, info.FullMethod)
+	if err != nil {
+		return nil, err
+	}
+
+	ctx = context.WithValue(ctx, clientIDKey, clientID)
+
+	return handler1(ctx, req)
+}
+
+func StartGRPCServer(address, certFilePath, privateKeyFilePath, vereignCertFilePath, vereignPrivateKeyFilePath, dataStorageAddress string) error {
+	pkgCertFile = certFilePath
+
+	// create a listener on TCP port
+	lis, err := net.Listen("tcp", address)
+	if err != nil {
+		return fmt.Errorf("failed to listen: %v", err)
+	}
+
+	// create a server instance
+	s := handler.KeyStorageServerImpl{
+		DataStorageUrl:            dataStorageAddress,
+		CertFilePath:              certFilePath,
+		VereignCertFilePath:       vereignCertFilePath,
+		VereignPrivateKeyFilePath: vereignPrivateKeyFilePath,
+	}
+
+	// Create the TLS credentials
+	creds, err := credentials.NewServerTLSFromFile(certFilePath, privateKeyFilePath)
+	if err != nil {
+		return fmt.Errorf("could not load TLS keys: %s", err)
+	}
+
+	// Create an array of gRPC options with the credentials
+	opts := []grpc.ServerOption{grpc.Creds(creds),
+		grpc.UnaryInterceptor(unaryInterceptor)}
+
+	// create a gRPC server object
+	grpcServer := grpc.NewServer(opts...)
+
+	// attach the CalcMinimumDistance service to the server
+	api.RegisterKeyStorageServer(grpcServer, &s)
+
+	// start the server
+	log.Printf("starting HTTP/2 gRPC server on %s", address)
+	if err := grpcServer.Serve(lis); err != nil {
+		return fmt.Errorf("failed to serve: %s", err)
+	}
+
+	return nil
+}
+
+func StartRESTServer(address, grpcAddress, certFile string) error {
+	ctx := context.Background()
+	ctx, cancel := context.WithCancel(ctx)
+	defer cancel()
+
+	mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher))
+
+	creds, err := credentials.NewClientTLSFromFile(certFile, "")
+	if err != nil {
+		return fmt.Errorf("could not load TLS certificate: %s", err)
+	}
+
+	// Setup the client gRPC options
+	opts := []grpc.DialOption{grpc.WithTransportCredentials(creds)}
+
+	// Register RedisStorageServer
+	err = api.RegisterKeyStorageHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
+	if err != nil {
+		return fmt.Errorf("could not register service RedisStorageServer: %s", err)
+	}
+
+	log.Printf("starting HTTP/1.1 REST server on %s", address)
+	http.ListenAndServe(address, mux)
+
+	return nil
+}
diff --git a/server/server_test.go b/server/server_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..aded86e9ddb5eecf3eda86d5b808103e96c093fc
--- /dev/null
+++ b/server/server_test.go
@@ -0,0 +1,261 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package server
+
+import (
+	"log"
+	"os"
+	"testing"
+	"time"
+
+	dataStorageServer "code.vereign.com/code/data-storage-agent/server"
+	"code.vereign.com/code/data-storage-agent/utils"
+	"code.vereign.com/code/viam-apis/authentication"
+	ksapi "code.vereign.com/code/viam-apis/key-storage-agent/api"
+	ksclient "code.vereign.com/code/viam-apis/key-storage-agent/client"
+	timestamp "github.com/golang/protobuf/ptypes/timestamp"
+)
+
+const (
+	dataStorageGrpcAddress    = "localhost:7777"
+	keyStorageGrpcAddress     = "localhost:7877"
+	certFilePath              = "../cert/server.crt"
+	privateKeyFilePath        = "../cert/server.key"
+	vereignCertFilePath       = "../cert/vereign_ca.cer"
+	vereignPrivateKeyFilePath = "../cert/vereign_ca.key"
+)
+
+func TestSetAndGetKeys(t *testing.T) {
+	dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFilePath)
+
+	keyStorageAuth := &authentication.Authentication{
+		Uuid:    "some-uuid",
+		Session: "some-session",
+	}
+
+	_, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session)
+
+	keyStorageClient := &ksclient.KeyStorageClientImpl{}
+	keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFilePath)
+	defer keyStorageClient.CloseClient()
+
+	uuid, statusList, _ := keyStorageClient.DoReserveKeyUUID()
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoReserveKeyUUID, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+
+	privateKey := &ksapi.Key{
+		Content: []byte{0, 1, 4},
+	}
+
+	statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PRIVATE, privateKey)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoSetKey, returned error: %s.", status.Code+":"+status.Description)
+			return
+		}
+	}
+
+	privateKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PRIVATE)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+			return
+		}
+	}
+	if privateKeyResult.Content == nil || !utils.CompareByteArrays(privateKeyResult.Content, []byte{0, 1, 4}) {
+		t.Errorf("DoGetKey, incorrect keyResult.Content, expected: %v, but was: %v",
+			[]byte{0, 1, 2}, privateKeyResult.Content)
+	}
+
+	// Test setting the same key twice
+	statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PRIVATE, privateKey)
+	for _, status := range statusList {
+		if status.StatusType != ksapi.StatusType_ERROR {
+			t.Errorf("DoSetKey, expected error, but got success")
+			return
+		}
+	}
+
+	publicKey := &ksapi.Key{
+		Content: []byte{3, 4, 2},
+	}
+
+	statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PUBLIC, publicKey)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoSetKey, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+
+	publicKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PUBLIC)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+	if publicKeyResult.Content == nil || !utils.CompareByteArrays(publicKeyResult.Content, []byte{3, 4, 2}) {
+		t.Errorf("DoGetKey, incorrect publicKeyResult.Content, expected: %v, but was: %v",
+			[]byte{3, 4, 2}, publicKeyResult.Content)
+	}
+
+	statusList, _ = keyStorageClient.DoRevoke(uuid)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoRevoke, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+	revokedPrivateKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PRIVATE)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+	if revokedPrivateKeyResult.Revoked == false {
+		t.Errorf("DoRevoke, key was not revoked")
+	}
+	revokedPublicKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PUBLIC)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+	if revokedPublicKeyResult.Revoked == false {
+		t.Errorf("DoRevoke, key was not revoked")
+	}
+}
+func TestGenerateKeyPairAndCertificate(t *testing.T) {
+	dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFilePath)
+
+	keyStorageAuth := &authentication.Authentication{
+		Uuid:    "some-uuid",
+		Session: "some-session",
+	}
+
+	_, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session)
+
+	keyStorageClient := &ksclient.KeyStorageClientImpl{}
+	keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFilePath)
+	defer keyStorageClient.CloseClient()
+
+	uuid, encryptedAesKey, privateKeyNonce, publicKeyNonce, statusList, _ := keyStorageClient.DoGenerateKeyPair(2048)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGenerateKeyPair, returned error: %s.", status.Code+":"+status.Description)
+			return
+		}
+	}
+	if uuid == "" {
+		t.Errorf("DoGenerateKeyPair, uuid is empty")
+		return
+	}
+
+	privateKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PRIVATE)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+			return
+		}
+	}
+	if privateKeyResult.Content == nil {
+		t.Errorf("DoGetKey, privateKeyResult.Content is nil")
+	}
+
+	publicKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PUBLIC)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+			return
+		}
+	}
+	if publicKeyResult.Content == nil {
+		t.Errorf("DoGetKey, publicKeyResult.Content is nil")
+	}
+
+	nowTime := time.Now()
+	nowTimeSeconds := time.Now().Unix()
+	nowTimeNanoSeconds := int32(nowTime.Sub(time.Unix(nowTimeSeconds, 0)))
+	notBefore := &timestamp.Timestamp{
+		Seconds: nowTimeSeconds,
+		Nanos:   nowTimeNanoSeconds,
+	}
+	timeAfterOneDay := nowTime.Add(1000000 * 3600 * 24)
+	secondsAfterOneDay := time.Now().Unix()
+	nanoSecondsAfterOneDay := int32(timeAfterOneDay.Sub(time.Unix(secondsAfterOneDay, 0)))
+	notAfter := &timestamp.Timestamp{
+		Seconds: secondsAfterOneDay,
+		Nanos:   nanoSecondsAfterOneDay,
+	}
+
+	certificateData := &ksapi.GenerateCertificateRequest_CertificateData{
+		Country:            "BG",
+		Organization:       "company",
+		OrganizationalUnit: "DEV",
+		CommonName:         "CN",
+		NotBefore:          notBefore,
+		NotAfter:           notAfter,
+		Host:               "abcde.com",
+	}
+
+	statusList, _ = keyStorageClient.DoGenerateCertificate(uuid, certificateData, encryptedAesKey, privateKeyNonce, publicKeyNonce)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGenerateCertificate, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+
+	certificate, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_CERTIFICATE)
+	for _, status := range statusList {
+		if status.StatusType == ksapi.StatusType_ERROR {
+			t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
+		}
+	}
+	if certificate == nil || certificate.Content == nil {
+		t.Errorf("DoGetKey, certificate is nil")
+	}
+}
+
+func TestMain(m *testing.M) {
+	// fire the gRPC server in a goroutine
+	go func() {
+		err := dataStorageServer.StartGRPCServer(dataStorageGrpcAddress, certFilePath, privateKeyFilePath)
+		if err != nil {
+			log.Fatalf("failed to start gRPC server: %s", err)
+		}
+	}()
+
+	// wait a second for the server to start
+	time.Sleep(time.Duration(1) * time.Second)
+
+	// fire the gRPC server in a goroutine
+	go func() {
+		err := StartGRPCServer(keyStorageGrpcAddress, certFilePath, privateKeyFilePath,
+			vereignCertFilePath, vereignPrivateKeyFilePath, dataStorageGrpcAddress)
+		if err != nil {
+			log.Fatalf("failed to start gRPC server: %s", err)
+		}
+	}()
+
+	// wait a second for the server to start
+	time.Sleep(time.Duration(1) * time.Second)
+
+	retCode := m.Run()
+	os.Exit(retCode)
+}
diff --git a/session/session.go b/session/session.go
new file mode 100644
index 0000000000000000000000000000000000000000..14793a89303df97561b0e64975fe40ab0a22ee2a
--- /dev/null
+++ b/session/session.go
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2018 Vereign AG [https://www.vereign.com]
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package session
+
+import (
+	client "code.vereign.com/code/viam-apis/data-storage-agent/client"
+)
+
+func CheckSession(uuid string, session string, sessionClient *client.DataStorageClientImpl) bool {
+	hasSession, _, err := sessionClient.HasSession(uuid, session)
+	if err != nil {
+		return false
+	}
+
+	return hasSession
+}