certlib

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2022 License: Apache-2.0 Imports: 8 Imported by: 0

README

Staex golang certification library

Go implementation of the custom certification library for the Staex project public key infrastructure.

Installation

General description

The purpose of the library is to parse and generate Staex custom certificates, which will be used in different tools (e.g. bootstrapping a new node or processing certificate signing requests).

The library implements methods to create a certificate, create a certificate signing request (CSR), sign a CSR, validate a certificate signature and renewing certificates.

It also allows the caller to get metadata information such as the expiration date of the certificate as well as the permissions on it.

The library uses the ECC (Elliptic Curve Cryptography) for calculating the signatures with the Curve25519. It is based on a Go implementation in Go’s standard library of the curve: https://godoc.org/golang.org/x/crypto/ed25519.

The permission format is specified in the MCC Security Proposal (https://gitlab.staex.io/stax.v2/mcc/-/blob/master/doc/README.md#permissions-and-authorization). The library does not validate nor process this field, it simply reads it and stores it and it is up to the library user to interpret it and apply it.

Elliptic Curve

In Elliptic Curve Cryptography there is a number of curves that can be used for cryptography purposes, and we have chosen to use the Curve25519 due to its multiple advantages (it is patent-free, it is very fast, it is designed for Elliptic Curve Diffie-Hellman key negotiation algorithm, there are no known backdoors or cryptographic flaws on it, and keys are just 256bit long while still providing high security).

Networking

To achieve secure networking between two peers, the public key cryptography is used. Public key cryptography works by distributing public keys while keeping a secret private key, thus, the certlib library provides an efficient mechanism to distribute the nodes' public keys.

Node ID

The node ID is the node's public key. It is a 256 bit long since Curve25519 public keys are that size. It is a random number, created with a cryptographically safe random number generator.

Safe communication

The originating node has the certificate of the target node, it will encrypt the message using a derived key calculated with its own private key and the public key of the target node. Afterward It will sign the message using its private key and send the message to the target node. The target node then receives the message and decrypts it by calculating the same derived key as the sender (by using the sender's public key and its private key). Afterward the target node checks the certificate, to make sure the sender can perform the actions the originating node requests. If the originating node is authorized, it will perform the requested operations.

Important: the private key is never sent to the remote side, it is used locally only.

Certificate format

Certificates are the way the Nodes validate and authorize each other. They contain four main elements:

  • The node's public key
  • The node's permissions
  • The expiration date
  • The root CA signature
  • The node's label
Node's key

The first part is the node's public key, this key is a 256-bit long random number. This is used to check the signatures in messages as well as to derive private keys using ECDH.

Permissions

Then come the permissions. This small block states which actions the node is allowed to perform, from the point of view of other nodes. The block is only 8 bit long.

Expiration date

The certificate will have the expiration date. When the date is past the certificate is invalid and should be rejected.

Node's label

The certificate will have the label. Using for human-readable name of node

The CA's signature is included in order to guarantee that this certificate can be trusted (and therefore grant the permissions specified in this certificate). It must contain a valid signature performed by the root CA. The signature has to sign the key, the permissions, the expiration date and the label together, to guarantee neither has been tampered with.

Permissions and authorization

The permission format is specified in the MCC Security Proposal (https://gitlab.staex.io/stax.v2/mcc/tree/mcc-security-proposal/doc/mep/mep1#permissions-and-authorization). The library does not validate nor process this field, it simply reads it and stores it and it is up to the library user to interpret it and apply it.

API

The library implements the following API:

package certlib

// ParseCertRequest parses a certificate request in binary format
func ParseCertRequest(data []byte) (CertificateRequest, error) {}

// NewCertRequest generates a new certificate request, generating also its public and private key, and adding the requested permissions to it.
func NewCertRequest(perms Permission, expiry time.Time, label string) (RequestData, error) {}

//RequestData is a struct to instantiate certificate request data fields
//The RequestData may or may not include a private key.
type RequestData struct {
	Request    CertificateRequest
	privateKey certlib_ed25519.PrivateKey
}

//CertificateRequest lists the methods to be implemented to be signed by the CA.
type CertificateRequest interface {

	//PublicKey returns the public key of the Certificate Request.
	PublicKey() []byte

	//Permissions returns the permissions requested in this Certificate Request.
	Permissions() Permission

	//Expiration returns the expiration date requested in this Certificate Request.
	Expiration() time.Time

	//Encode encodes the Certificate Request in binary format.
	Encode() []byte

	//Label returns the label of the Certificate Request.
	Label() []byte
}

// NewSelfSignedCert creates a new certificate, together with public and private keys and expiry. Finally, it signs the certificate with the same key. This is intended to be used as a CA or a test certificate.
func NewSelfSignedCert(permissions Permission, expiry time.Time, label string) (CertificateData, error) {}

// ParseCert will parse the given certificate in binary format.
func ParseCert(data []byte) (Certificate, error) {}

//ParseCertBase64 will parse the given certificate encoded in base64 string
func ParseCertBase64(cert string) (Certificate, error) {}

// ParsePrivateKey will validate the given private key.
func ParsePrivateKey(data []byte) ([]byte, error) {}

//ParsePrivateKeyBase64 will parse the given private key encoded in base64 string
func ParsePrivateKeyBase64(privKey string) ([]byte, error) {}

//EncodeBase64PrivateKey encodes private key in base64 string.
func EncodeBase64PrivateKey(privateKey []byte) string {}

//CertificateData is a struct to instantiate certificate data fields.
// The goal - separate storage for certificate and it's private key
type CertificateData struct {
	Cert       Certificate
	privateKey certlib_ed25519.PrivateKey
}

//Certificate represents a certificate, with its public key, permissions and expiry.
type Certificate interface {

	//PublicKey returns the public key of this certificate.
	PublicKey() []byte

	//Expiry returns the expiry date of this certificate.
	Expiry() time.Time

	//Permissions returns the permissions of this certificate.
	Permissions() Permission

	//Signature returns the signature of this certificate (the signature of the CA that issued this cert).
	Signature() []byte

	//SignData signs a data block and appends the signature at the end.
	SignData(privateKey []byte, data []byte) ([]byte, error)

	//VerifySignedData verifies that the signature of a data block is valid and was done by this certificate.
	VerifySignedData(data []byte) (bool, error)

	//VerifyDataSignature verifies that the signature is valid for the message and was done by this certificate.
	VerifyDataSignature(message []byte, signature []byte) (bool, error)

	//SignCertRequest signs given request and returns a certificate with expiration date
	//with the public/private key and permissions provided in the request.
	SignCertRequest(privateKey []byte, cert CertificateRequest, expiry time.Time) (Certificate, error)

	//Encode encodes the certificate in its binary format.
	Encode() []byte

	//EncodeBase64 encodes certificate in base64 string.
	EncodeBase64() string

	//IsValid checks that this certificate's signature is valid and was done by the given CA.
	IsValid(ca Certificate) bool

	//SharedSecret prepares a shared secret for the certificate owner and for another party.
	SharedSecretCert(privateKey []byte, certificate Certificate) (*Secret, error)

	//SharedSecretPub prepares a shared secret for the certificate owner and for another party.
	SharedSecret(privateKey []byte, pubKey []byte) (*Secret, error)

	// HavePermissions checks if certificate has provided permissions. It is possible to check multiple
	// permissions by applying logical OR on Permissions.
	HavePermissions(perm Permission) bool

	//Label returns string representation of the label of this certificate.
	Label() string
}

Usage

To use the certlib library in the Go project one must import the "certlib" package:

import (
  "github.com/staex-mcc/certlib"
)
CSR

With the certlib one can create a certificate signing request (CSR) with NewCertRequest function. The public and private keys will be created, they should be stored for future use. Then, the Encode function serializes the CSR (without private key) and the serialized data can be posted to the authority.

Signing the CSR

The Certification Authority can parse received CSR (ParseCertRequest), validate the sender, sign the request (SignCertRequest), Encode it, and send it back with the CA signature.

Validating the certificate

Having the public key of the CA one can validate issued certificate using IsValid function.

Signing data

Any binary data can be signed with SignData function. The signature is added at the end of the signed data.

Verification of signed data

Having the public key of the data sender one can check the message authenticity by calling VerifySignedData function.

Documentation

Overview

Package certlib contains the implemetation of the custom certifiaction library. The purpose of the library is to parse and generate Staex custom certificates, which will be used in different tools (e.g. bootstrapping a new node or processing CSRs). The library implements methods to create a certificate, create a certificate signing request (CSR), sign a CSR, validate a certificate signature and renewing certificates. It also allows the caller to get metadata information such as the expiration date of the certificate as well as the permissions on it. The library uses the ECC (Elliptic Curve Cryptography) for calculating the signatures with the Curve25519. It is based on a Go implementation in Go’s standard library of the curve: https://godoc.org/golang.org/x/crypto/ed25519. The permissions are contained in a single byte. The library does not validate nor process this field, it simply reads it and stores it and it is up to the library user to interpret it and apply it.

Index

Constants

View Source
const (
	// LabelSize represents the size of the label of a certificate
	LabelSize = 30

	// CertificateSize represents the size of a CertificateSize
	CertificateSize = certificateRequestSize + certlib_ed25519.SignatureSize
	// PrivateKeySize represents the size of the private key of a certificate
	PrivateKeySize = certlib_ed25519.PrivateKeySize
)
View Source
const (
	GetValuesPermission        Permission = 1
	AddValuesPermission                   = 2
	RegisterServicesPermission            = 4
	LookupServicesPermission              = 8
	OpenChannelsPermission                = 16
	RelayPermission                       = 32
	AllPermissions                        = 255
)

Variables

View Source
var ErrDataTooShort = errors.New("data to process is too short")

ErrDataTooShort is the predefined error returned when the given data is equal to or shorter then size of the signature.

View Source
var ErrExpired = errors.New("certificate has expired")

ErrExpired is the predefined error returned when the expiration date provided in the request is past.

View Source
var ErrInvalidData = errors.New("data has wrong length")

ErrInvalidData is the predefined error returned when provided data is of wrong length.

View Source
var ErrInvalidExpDate = errors.New("expiration date must be in future")

ErrInvalidExpDate is the predefined error returned when the expiration date provided is past.

View Source
var ErrInvalidLabelSize = errors.New("label has an incorrect size")

ErrInvalidLabelSize is the predefined error returned when the the label has an incorrect size.

View Source
var ErrInvalidSignatureSize = errors.New("signature has an incorrect size")

ErrInvalidSignatureSize is the predefined error returned when the the signature has an incorrect size.

View Source
var ErrNoData = errors.New("no data to process")

ErrNoData is the predefined error returned when provided data is empty.

View Source
var ErrNoPrivateKey = errors.New("no private key")

ErrNoPrivateKey is the predefined error returned when there is no private key included in the request.

View Source
var ErrPrivKeyInvalidLen = errors.New("private key has invalid length")

ErrPrivKeyInvalidLen is the predefined error returned when private key has invalid length

Functions

func EncodeBase64PrivateKey

func EncodeBase64PrivateKey(privateKey []byte) string

EncodeBase64PrivateKey encodes private key in base64 string.

func ExtractSignature

func ExtractSignature(data []byte) ([]byte, []byte, error)

ExtractSignature separates and returns the message and the signature.

func ParsePrivateKey

func ParsePrivateKey(data []byte) ([]byte, error)

func ParsePrivateKeyBase64

func ParsePrivateKeyBase64(privKey string) ([]byte, error)

ParsePrivateKeyBase64 will parse the given private key encoded in base64 string

func SodiumInit

func SodiumInit() error

Types

type Certificate

type Certificate interface {

	//PublicKey returns the public key of this certificate.
	PublicKey() []byte

	//Expiry returns the expiry date of this certificate.
	Expiry() time.Time

	//Permissions returns the permissions of this certificate.
	Permissions() Permission

	//Signature returns the signature of this certificate (the signature of the CA that issued this cert).
	Signature() []byte

	//SignData signs a data block and appends the signature at the end.
	SignData(privateKey []byte, data []byte) ([]byte, error)

	//VerifySignedData verifies that the signature of a data block is valid and was done by this certificate.
	VerifySignedData(data []byte) (bool, error)

	//VerifyDataSignature verifies that the signature is valid for the message and was done by this certificate.
	VerifyDataSignature(message []byte, signature []byte) (bool, error)

	//SignCertRequest signs given request and returns a certificate with expiration date
	//with the public/private key and permissions provided in the request.
	SignCertRequest(privateKey []byte, cert CertificateRequest, expiry time.Time) (Certificate, error)

	//Encode encodes the certificate in its binary format.
	Encode() []byte

	//EncodeBase64 encodes certificate in base64 string.
	EncodeBase64() string

	//IsValid checks that this certificate's signature is valid and was done by the given CA.
	IsValid(ca Certificate) bool

	//SharedSecret prepares a shared secret for the certificate owner and for another party.
	SharedSecretCert(privateKey []byte, certificate Certificate) (*Secret, error)

	//SharedSecretPub prepares a shared secret for the certificate owner and for another party.
	SharedSecret(privateKey []byte, pubKey []byte) (*Secret, error)

	// HavePermissions checks if certificate has provided permissions. It is possible to check multiple
	// permissions by applying logical OR on Permissions.
	HavePermissions(perm Permission) bool

	//Label returns string representation of the label of this certificate.
	Label() string
}

Certificate represents a certificate, with its public key, permissions and expiry.

func ComposeCertificate

func ComposeCertificate(pubKey []byte, perms Permission, exp uint32, sig []byte, label string) (Certificate, error)

ComposeCertificate creates a certificate struct from given public key, permissions, expiration date, signature and label.

func ParseCert

func ParseCert(data []byte) (Certificate, error)

ParseCert will parse the given certificate in binary format.

func ParseCertBase64

func ParseCertBase64(cert string) (Certificate, error)

ParseCertBase64 will parse the given certificate encoded in base64 string

type CertificateContainer

type CertificateContainer struct {
	// contains filtered or unexported fields
}

CertificateContainer is a struct to instantiate certificate fields and it implements the Certificate interface methods.

func (*CertificateContainer) Encode

func (c *CertificateContainer) Encode() []byte

Encode encodes the certificate in its binary format.

func (*CertificateContainer) EncodeBase64

func (c *CertificateContainer) EncodeBase64() string

EncodeBase64 encodes certificate in base64 string.

func (CertificateContainer) Expiry

func (c CertificateContainer) Expiry() time.Time

Expiry returns the signature of the Certificate created by signing the contained data.

func (*CertificateContainer) HavePermissions

func (c *CertificateContainer) HavePermissions(perm Permission) bool

HavePermissions checks if certificate has provided permissions. It is possible to check multiple permissions by applying logical OR on Permissions.

func (*CertificateContainer) IsValid

func (c *CertificateContainer) IsValid(ca Certificate) bool

IsValid checks that this certificate's signature is valid and was done by the given CA.

func (*CertificateContainer) Label

func (c *CertificateContainer) Label() string

Label returns string representation of the label of the Certificate.

func (*CertificateContainer) Permissions

func (c *CertificateContainer) Permissions() Permission

Permissions returns the permissions requested in this Certificate.

func (*CertificateContainer) PublicKey

func (c *CertificateContainer) PublicKey() []byte

PublicKey returns the public key of the Certificate.

func (*CertificateContainer) SharedSecret

func (c *CertificateContainer) SharedSecret(privateKey, pubKey []byte) (*Secret, error)

SharedSecret converts the ed25519 private and public keys provided to curve25519. It returns the product private*public key from `c` and `certificate` respectively.

func (*CertificateContainer) SharedSecretCert

func (c *CertificateContainer) SharedSecretCert(privateKey []byte, certificate Certificate) (*Secret, error)

SharedSecretCert converts the ed25519 private and public keys provided to curve25519. It returns the product private*public key from `c` and `certificate` respectively.

func (*CertificateContainer) SignCertRequest

func (c *CertificateContainer) SignCertRequest(privateKey []byte,
	cert CertificateRequest, expiry time.Time) (Certificate, error)

SignCertRequest signs given request and returns a certificate with expiration date with the public key and permissions provided in the request.

func (*CertificateContainer) SignData

func (c *CertificateContainer) SignData(privateKey []byte, data []byte) ([]byte, error)

SignData signs a data block and appends the signature at the end.

func (*CertificateContainer) Signature

func (c *CertificateContainer) Signature() []byte

Signature returns the signature of the Certificate created by signing the contained data.

func (*CertificateContainer) VerifyDataSignature

func (c *CertificateContainer) VerifyDataSignature(message []byte, signature []byte) (bool, error)

VerifyDataSignature verifies that the signature is valid for the message and was done by this certificate.

func (*CertificateContainer) VerifySignedData

func (c *CertificateContainer) VerifySignedData(data []byte) (bool, error)

VerifySignedData verifies that the signature of a data block is valid and was done by this certificate. It calls ExtractSignature().

type CertificateData

type CertificateData struct {
	Cert Certificate
	// contains filtered or unexported fields
}

CertificateData is a struct to instantiate certificate data fields. The goal - separate storage for certificate and it's private key

func NewSelfSignedCert

func NewSelfSignedCert(permissions Permission, expiry time.Time, label string) (CertificateData, error)

NewSelfSignedCert creates a new certificate, together with public and private keys and expiry. Finally, it signs the certificate with the same key. This is intended to be used as a CA or a test certificate. An error can be returned when the underlying platform does not support cryptographically safe random number generator.

func (*CertificateData) PrivateKey

func (cd *CertificateData) PrivateKey() ([]byte, error)

PrivateKey returns the private key of the Certificate. If this Certificate does not include a private key, it will return an error.

type CertificateRequest

type CertificateRequest interface {

	//PublicKey returns the public key of the Certificate Request.
	PublicKey() []byte

	//Permissions returns the permissions requested in this Certificate Request.
	Permissions() Permission

	//Expiration returns the expiration date requested in this Certificate Request.
	Expiration() time.Time

	//Encode encodes the Certificate Request in binary format.
	Encode() []byte

	//EncodeBase64 encodes the Certificate Request in base64 string.
	EncodeBase64() string

	//Label returns string representation of the label of this Certificate Request.
	Label() string
}

CertificateRequest lists the methods to be implemented to be signed by the CA.

func ComposeRequest

func ComposeRequest(pubKey []byte, perms Permission, expDate time.Time, label string) (CertificateRequest, error)

ComposeRequest creates a request from given keys, permissions, expiration date and label.

func ParseCertRequest

func ParseCertRequest(data []byte) (CertificateRequest, error)

ParseCertRequest parses a certificate request in binary format

func ParseCertRequestBase64

func ParseCertRequestBase64(cert string) (CertificateRequest, error)

ParseCertRequestBase64 will parse the given request encoded in base64 string

type Permission

type Permission uint8

type Request

type Request struct {
	// contains filtered or unexported fields
}

Request is a struct to instantiate certificate request fields and it implements the CertificateRequest lists interface methods.

func (*Request) Encode

func (r *Request) Encode() []byte

Encode returns byte array containing data of this certificate request.

func (*Request) EncodeBase64

func (r *Request) EncodeBase64() string

EncodeBase64 encodes request in base64 string.

func (*Request) Expiration

func (r *Request) Expiration() time.Time

Expiration returns the expiration date requested in this Certificate Request.

func (*Request) Label

func (r *Request) Label() string

Label returns string representation of the label of the Certificate Request.

func (*Request) Permissions

func (r *Request) Permissions() Permission

Permissions returns the permissions requested in this Certificate Request.

func (*Request) PublicKey

func (r *Request) PublicKey() []byte

PublicKey returns the public key of the Certificate Request.

type RequestData

type RequestData struct {
	Request CertificateRequest
	// contains filtered or unexported fields
}

RequestData is a struct to instantiate certificate request data fields The RequestData may or may not include a private key.

func NewCertRequest

func NewCertRequest(perms Permission, expiry time.Time, label string) (RequestData, error)

NewCertRequest generates a new certificate request, generating also its public and private key, and adding the requested permissions and expiration date to it. The error can be returned by the ed25519 library, e.g. when the platform does not support cryptographically safe random number generator.

func (*RequestData) PrivateKey

func (r *RequestData) PrivateKey() ([]byte, error)

PrivateKey returns the private key of the Certificate Request. If this Certificate Request does not include a private key, it will return an error.

type Secret

type Secret [32]byte

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL