Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NOISSUE - Add DTLS config to coap-cli #11

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0

all:
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -o build/coap-cli-linux cmd/main.go
CGO_ENABLED=0 GOOS=darwin go build -ldflags "-s -w" -o build/coap-cli-darwin cmd/main.go
CGO_ENABLED=0 GOOS=windows go build -ldflags "-s -w" -o build/coap-cli-windows cmd/main.go
INSTALL_DIR=/usr/local/bin
BUILD_DIR=build
BUILD_FLAGS=-ldflags "-s -w"

.PHONY: all linux darwin windows install install-linux

all: linux darwin windows

linux:
CGO_ENABLED=0 GOOS=linux go build $(BUILD_FLAGS) -o $(BUILD_DIR)/coap-cli-linux cmd/main.go

darwin:
CGO_ENABLED=0 GOOS=darwin go build $(BUILD_FLAGS) -o $(BUILD_DIR)/coap-cli-darwin cmd/main.go

windows:
CGO_ENABLED=0 GOOS=windows go build $(BUILD_FLAGS) -o $(BUILD_DIR)/coap-cli-windows cmd/main.go

install: install-linux

install-linux:
@cp $(BUILD_DIR)/coap-cli-linux $(INSTALL_DIR)/coap-cli || { echo "Installation failed"; exit 1; }

clean:
rm -rf $(BUILD_DIR)/*
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -18,10 +18,13 @@ Available Commands:

Flags:
-a, --auth string Auth
-A, --ca-file string Client CA file
-C, --cert-file string Client certificate file
-c, --content-format int Content format (default 50)
-h, --help help for coap-cli
-H, --host string Host (default "localhost")
-k, --keep-alive uint Send a ping after interval seconds of inactivity. If not specified (or 0), keep-alive is disabled (default).
-K, --key-file string Client key file
-m, --max-retries uint32 Max retries for keep alive (default 10)
-O, --options num,text Add option num with contents of text to the request. If the text begins with 0x, then the hex text (two [0-9a-f] per byte) is converted to binary data.
-p, --port string Port (default "5683")
@@ -44,6 +47,10 @@ coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --a
coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --options 6,0x00 --options 15,auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb
```

```bash
coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --options 6,0x00 --options 15,auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb --ca-file ssl/certs/ca.crt --cert-file ssl/certs/client.crt --key-file ssl/certs/client.key
```

```bash
coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world"
```
@@ -55,3 +62,6 @@ coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --
```bash
coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -options 15,auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" -H 0.0.0.0 -p 5683
```
```bash
coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" --ca-file ssl/certs/ca.crt --cert-file ssl/certs/client.crt --key-file ssl/certs/client.key
```
143 changes: 97 additions & 46 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,10 @@ package main

import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"errors"
"fmt"
"log"
"os"
@@ -17,25 +20,13 @@ import (

coap "github.com/absmach/coap-cli/coap"
"github.com/fatih/color"
piondtls "github.com/pion/dtls/v2"
coapmsg "github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/plgd-dev/go-coap/v3/message/pool"
"github.com/spf13/cobra"
)

var (
host string
port string
contentFormat int
auth string
observe bool
data string
options []string
keepAlive uint64
verbose bool
maxRetries uint32
)

const verboseFmt = `Date: %s
Code: %s
Type: %s
@@ -44,6 +35,8 @@ Message-ID: %d
`

func main() {
req := &request{}

rootCmd := &cobra.Command{
Use: "coap-cli <method> <URL> [options]",
Short: "CLI for CoAP",
@@ -54,46 +47,49 @@ func main() {
Short: "Perform a GET request on a COAP resource",
Example: "coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -a 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -H localhost -p 5683 -O 17,50 -o \n" +
"coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb --host localhost --port 5683 --options 17,50 --observe",
Run: runCmd(codes.GET),
Run: runCmd(req, codes.GET),
}
getCmd.Flags().BoolVarP(&observe, "observe", "o", false, "Observe resource")
getCmd.Flags().BoolVarP(&req.observe, "observe", "o", false, "Observe resource")

putCmd := &cobra.Command{
Use: "put <url>",
Short: "Perform a PUT request on a COAP resource",
Example: "coap-cli put /test -H coap.me -p 5683 -c 50 -d 'hello, world'\n" +
"coap-cli put /test --host coap.me --port 5683 --content-format 50 --data 'hello, world'",
Run: runCmd(codes.PUT),
Run: runCmd(req, codes.PUT),
}
putCmd.Flags().StringVarP(&data, "data", "d", "", "Data")
putCmd.Flags().StringVarP(&req.data, "data", "d", "", "Data")

postCmd := &cobra.Command{
Use: "post <url>",
Short: "Perform a POST request on a COAP resource",
Example: "coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -a 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -H localhost -p 5683 -c 50 -d 'hello, world'\n" +
"coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic --auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb --host localhost --port 5683 --content-format 50 --data 'hello, world'",
Run: runCmd(codes.POST),
Run: runCmd(req, codes.POST),
}
postCmd.Flags().StringVarP(&data, "data", "d", "", "Data")
postCmd.Flags().StringVarP(&req.data, "data", "d", "", "Data")

deleteCmd := &cobra.Command{
Use: "delete <url>",
Short: "Perform a DELETE request on a COAP resource",
Example: "coap-cli delete /test -H coap.me -p 5683 -c 50 -d 'hello, world' -O 17,50\n" +
"coap-cli delete /test --host coap.me --port 5683 --content-format 50 --data 'hello, world' --options 17,50",
Run: runCmd(codes.DELETE),
Run: runCmd(req, codes.DELETE),
}
deleteCmd.Flags().StringVarP(&data, "data", "d", "", "Data")
deleteCmd.Flags().StringVarP(&req.data, "data", "d", "", "Data")

rootCmd.AddCommand(getCmd, putCmd, postCmd, deleteCmd)
rootCmd.PersistentFlags().StringVarP(&host, "host", "H", "localhost", "Host")
rootCmd.PersistentFlags().StringVarP(&port, "port", "p", "5683", "Port")
rootCmd.PersistentFlags().StringVarP(&auth, "auth", "a", "", "Auth")
rootCmd.PersistentFlags().IntVarP(&contentFormat, "content-format", "c", 50, "Content format")
rootCmd.PersistentFlags().StringArrayVarP(&options, "options", "O", []string{}, "Add option num with contents of text to the request. If the text begins with 0x, then the hex text (two [0-9a-f] per byte) is converted to binary data.")
rootCmd.PersistentFlags().Uint64VarP(&keepAlive, "keep-alive", "k", 0, "Send a ping after interval seconds of inactivity. If not specified (or 0), keep-alive is disabled (default).")
rootCmd.PersistentFlags().Uint32VarP(&maxRetries, "max-retries", "m", 10, "Max retries for keep alive")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
rootCmd.PersistentFlags().StringVarP(&req.host, "host", "H", "localhost", "Host")
rootCmd.PersistentFlags().StringVarP(&req.port, "port", "p", "5683", "Port")
rootCmd.PersistentFlags().StringVarP(&req.auth, "auth", "a", "", "Auth")
rootCmd.PersistentFlags().IntVarP(&req.contentFormat, "content-format", "c", 50, "Content format")
rootCmd.PersistentFlags().StringArrayVarP(&req.options, "options", "O", []string{}, "Add option num with contents of text to the request. If the text begins with 0x, then the hex text (two [0-9a-f] per byte) is converted to binary data.")
rootCmd.PersistentFlags().Uint64VarP(&req.keepAlive, "keep-alive", "k", 0, "Send a ping after interval seconds of inactivity. If not specified (or 0), keep-alive is disabled (default).")
rootCmd.PersistentFlags().Uint32VarP(&req.maxRetries, "max-retries", "m", 10, "Max retries for keep alive")
rootCmd.PersistentFlags().BoolVarP(&req.verbose, "verbose", "v", false, "Verbose output")
rootCmd.PersistentFlags().StringVarP(&req.certFile, "cert-file", "C", "", "Client certificate file")
rootCmd.PersistentFlags().StringVarP(&req.keyFile, "key-file", "K", "", "Client key file")
rootCmd.PersistentFlags().StringVarP(&req.clientCAFile, "ca-file", "A", "", "Client CA file")

if err := rootCmd.Execute(); err != nil {
log.Fatalf("Error executing command: %v", err)
@@ -126,14 +122,18 @@ func printMsg(m *pool.Message, verbose bool) {
}
}

func makeRequest(code codes.Code, args []string) {
client, err := coap.NewClient(host+":"+port, keepAlive, maxRetries)
func makeRequest(req *request, args []string) {
dtlsConfig, err := req.createDTLSConfig()
if err != nil {
log.Fatalf("Error creating DTLS config: %v", err)
}
client, err := coap.NewClient(req.host+":"+req.port, req.keepAlive, req.maxRetries, dtlsConfig)
if err != nil {
log.Fatalf("Error coap creating client: %v", err)
}

var opts coapmsg.Options
for _, optString := range options {
for _, optString := range req.options {
opt := strings.Split(optString, ",")
if len(opt) < 2 {
log.Fatal("Invalid option format")
@@ -153,20 +153,20 @@ func makeRequest(code codes.Code, args []string) {
opts = append(opts, coapmsg.Option{ID: coapmsg.OptionID(optId), Value: []byte(opt[1])})
}
}
if auth != "" {
opts = append(opts, coapmsg.Option{ID: coapmsg.URIQuery, Value: []byte("auth=" + auth)})
if req.auth != "" {
opts = append(opts, coapmsg.Option{ID: coapmsg.URIQuery, Value: []byte("auth=" + req.auth)})
}
if opts.HasOption(coapmsg.Observe) {
if value, _ := opts.GetBytes(coapmsg.Observe); len(value) == 1 && value[0] == 0 && !observe {
observe = true
if value, _ := opts.GetBytes(coapmsg.Observe); len(value) == 1 && value[0] == 0 && !req.observe {
req.observe = true
}
}

switch code {
switch req.code {
case codes.GET:
switch {
case observe:
obs, err := client.Receive(args[0], verbose, opts...)
case req.observe:
obs, err := client.Receive(args[0], req.verbose, opts...)
if err != nil {
log.Fatalf("Error observing resource: %v", err)
}
@@ -183,28 +183,79 @@ func makeRequest(code codes.Code, args []string) {
}
log.Fatalf("Observation terminated: %v", err)
default:
res, err := client.Send(args[0], code, coapmsg.MediaType(contentFormat), nil, opts...)
res, err := client.Send(args[0], req.code, coapmsg.MediaType(req.contentFormat), nil, opts...)
if err != nil {
log.Fatalf("Error sending message: %v", err)
}
printMsg(res, verbose)
printMsg(res, req.verbose)
}
default:
pld := strings.NewReader(data)
res, err := client.Send(args[0], code, coapmsg.MediaType(contentFormat), pld, opts...)
pld := strings.NewReader(req.data)
res, err := client.Send(args[0], req.code, coapmsg.MediaType(req.contentFormat), pld, opts...)
if err != nil {
log.Fatalf("Error sending message: %v", err)
}
printMsg(res, verbose)
printMsg(res, req.verbose)
}
}

func runCmd(code codes.Code) func(cmd *cobra.Command, args []string) {
func runCmd(req *request, code codes.Code) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
fmt.Fprintf(os.Stdout, color.YellowString("\nusage: %s\n\n"), cmd.Use)
return
}
makeRequest(code, args)
req.code = code
makeRequest(req, args)
}
}

type request struct {
code codes.Code
host string
port string
contentFormat int
auth string
observe bool
data string
options []string
keepAlive uint64
verbose bool
maxRetries uint32
certFile string
keyFile string
clientCAFile string
}

func (r *request) createDTLSConfig() (*piondtls.Config, error) {
if r.certFile == "" || r.keyFile == "" {
return nil, nil
}
dc := &piondtls.Config{}
cert, err := tls.LoadX509KeyPair(r.certFile, r.keyFile)
if err != nil {
return nil, errors.Join(errors.New("failed to load certificates"), err)
}
dc.Certificates = []tls.Certificate{cert}
rootCA, err := loadCertFile(r.clientCAFile)
if err != nil {
return nil, errors.Join(errors.New("failed to load Client CA"), err)
}
if len(rootCA) > 0 {
if dc.RootCAs == nil {
dc.RootCAs = x509.NewCertPool()
}
if !dc.RootCAs.AppendCertsFromPEM(rootCA) {
return nil, errors.New("failed to append root ca tls.Config")
}
}
dc.InsecureSkipVerify = true
return dc, nil
}

func loadCertFile(certFile string) ([]byte, error) {
if certFile != "" {
return os.ReadFile(certFile)
}
return []byte{}, nil
}
12 changes: 10 additions & 2 deletions coap/client.go
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ import (
"log"
"time"

piondtls "github.com/pion/dtls/v2"
"github.com/plgd-dev/go-coap/v3/dtls"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/plgd-dev/go-coap/v3/message/pool"
@@ -39,12 +41,18 @@ type Client struct {
}

// NewClient returns new CoAP client connecting it to the server.
func NewClient(addr string, keepAlive uint64, maxRetries uint32) (Client, error) {
func NewClient(addr string, keepAlive uint64, maxRetries uint32, dtlsConfig *piondtls.Config) (Client, error) {
var dialOptions []udp.Option
if keepAlive > 0 {
dialOptions = append(dialOptions, options.WithKeepAlive(maxRetries, time.Duration(keepAlive)*time.Second, onInactive))
}
c, err := udp.Dial(addr, dialOptions...)
var c *client.Conn
var err error
if dtlsConfig != nil {
c, err = dtls.Dial(addr, dtlsConfig, dialOptions...)
} else {
c, err = udp.Dial(addr, dialOptions...)
}
if err != nil {
return Client{}, errors.Join(errDialFailed, err)
}
40 changes: 40 additions & 0 deletions examples/coapme/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
host="coap.me"
port="5683"
testPath="/test"
largePath="/large"
etagPath="/etag"
payload="Hello world from absmach/coap-cli"

#Get
echo "Sending GET request to $host:$port$testPath"
coap-cli get $testPath -H $host -p $port
sleep 1

#Get with blockwise transfer
echo "Sending GET request with blockwise transfer to $host:$port$testPath"
coap-cli get $largePath -H $host -p $port
sleep 1

#Post
echo "Sending POST request to $host:$port$testPath"
coap-cli post $testPath -H $host -p $port -d $payload
sleep 1

#Post with content format
echo "Sending POST request with content format to $host:$port$testPath"
coap-cli post $testPath -H $host -p $port -d $payload -c 50
sleep 1

#Post with authentication
echo "Sending POST request with authentication to $host:$port$testPath"
coap-cli post $testPath -H $host -p $port -d $payload --auth "test"
sleep 1

#Put
echo "Sending PUT request to $host:$port$testPath"
coap-cli put $testPath -H $host -p $port -d $payload
sleep 1

#Delete
echo "Sending DELETE request to $host:$port$testPath"
coap-cli delete $testPath -H $host -p $port
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -4,20 +4,22 @@ go 1.22

require (
github.com/fatih/color v1.17.0
github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0
github.com/plgd-dev/go-coap/v3 v3.3.4
github.com/spf13/cobra v1.8.0
)

require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dsnet/golib/memfile v1.0.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/transport/v3 v3.0.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/golib/memfile v1.0.0 h1:J9pUspY2bDCbF9o+YGwcf3uG6MdyITfh/Fk3/CaEiFs=
github.com/dsnet/golib/memfile v1.0.0/go.mod h1:tXGNW9q3RwvWt1VV2qrRKlSSz0npnh12yftCSCy2T64=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
@@ -26,8 +27,9 @@ github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkL
github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
github.com/plgd-dev/go-coap/v3 v3.3.4 h1:clDLFOXXmXfhZqB0eSk6WJs2iYfjC2J22Ixwu5MHiO0=
github.com/plgd-dev/go-coap/v3 v3.3.4/go.mod h1:vxBvAgXxL+Au/58XYTM+8ftqO/ycFC9/Dh+uI72xYjA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
64 changes: 64 additions & 0 deletions ssl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0

CRT_LOCATION = certs
O = absmach
OU_CA = absmach_ca
OU_CRT = absmach_crt
EA = info@absmach.com
CLIENT_CN = coap-cli-client
CRT_FILE_NAME = client
CN_CA = Absmach_Self_Signed_CA

define CERT_CONFIG
[ca]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always

[req]
req_extensions = v3_req
distinguished_name = dn
prompt = no

[dn]
CN = $(COMMON_NAME)
C = FR
ST = FR
L = PARIS
O = absmach
OU = absmach

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = $(COMMON_NAME)
endef


.PHONY: all clean_certs client_cert client_cert_revoked client_cert_unknown ca

# Generate all client certificates
all: clean_certs ca client_cert client_cert_revoked client_cert_unknown

ca:
openssl req -newkey rsa:2048 -x509 -nodes -sha512 -days 1095 \
-keyout $(CRT_LOCATION)/ca.key -out $(CRT_LOCATION)/ca.crt -subj "/CN=$(CN_CA)/O=$(O)/OU=$(OU_CA)/emailAddress=$(EA)"

client_cert:
# Create absmach client key and CSR.
openssl req -new -sha256 -newkey rsa:4096 -nodes -keyout $(CRT_LOCATION)/$(CRT_FILE_NAME).key \
-out $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -subj "/CN=$(CLIENT_CN)/O=$(O)/OU=$(OU_CRT)/emailAddress=$(EA)"

# Sign client CSR.
openssl x509 -req -days 730 -in $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -CA $(CRT_LOCATION)/ca.crt -CAkey $(CRT_LOCATION)/ca.key -CAcreateserial -out $(CRT_LOCATION)/$(CRT_FILE_NAME).crt

# Remove CSR.
rm $(CRT_LOCATION)/$(CRT_FILE_NAME).csr

clean_certs:
rm -f $(CRT_LOCATION)/*.crt
rm -f $(CRT_LOCATION)/*.key
rm -f $(CRT_LOCATION)/*.srl
22 changes: 22 additions & 0 deletions ssl/certs/ca.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIULa101cRg3Vvf+M/fLHj8pYTJIyEwDQYJKoZIhvcNAQEN
BQAwaTEfMB0GA1UEAwwWQWJzbWFjaF9TZWxmX1NpZ25lZF9DQTEQMA4GA1UECgwH
YWJzbWFjaDETMBEGA1UECwwKYWJzbWFjaF9jYTEfMB0GCSqGSIb3DQEJARYQaW5m
b0BhYnNtYWNoLmNvbTAeFw0yNDA1MDcwODUyMTFaFw0yNzA1MDcwODUyMTFaMGkx
HzAdBgNVBAMMFkFic21hY2hfU2VsZl9TaWduZWRfQ0ExEDAOBgNVBAoMB2Fic21h
Y2gxEzARBgNVBAsMCmFic21hY2hfY2ExHzAdBgkqhkiG9w0BCQEWEGluZm9AYWJz
bWFjaC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrtBFpQ4SB
5QCN/kgl3974UvUe/mcar1AEnR3rBRRdpQV4fxifDN/GBzuYt0xhfaQcPNBX8pL1
luhHsOEkS1Q1o0TsKCL+2o6x98ez0+Q0YDRCBFs027YCyBRzZB7zRwSno82A8st+
XjzF53kskXwGvv+3dv/XMc1BcO6lhVdNy65cBIhEc15Jpeq8hy27lRPIAcjldEnj
5A6BvUrCBqD1FEXobqxAYeQ8vSpqZhaa+C1p03zz0yZ4aCkUBciVoBan8dAB9oKo
AL36oSnGCTyxfXLFCGuIBqhK1dlMX/AnBy6FeCa+yAL6AsC873xevcoYEUCrcPme
FM89BFy7vi3lAgMBAAGjUzBRMB0GA1UdDgQWBBRynRpuEdb2USRiLagfJJYTcJSa
JDAfBgNVHSMEGDAWgBRynRpuEdb2USRiLagfJJYTcJSaJDAPBgNVHRMBAf8EBTAD
AQH/MA0GCSqGSIb3DQEBDQUAA4IBAQBroEYZ6yn0WBzbfEwT8V/yJzFqEh1D+Dwk
OrvNluYCG5Bk8UJtqirt3Hh/C1y0/84koSiWbr2ODV8Q2CfUW2DVIL7JS7WapC5K
lg5KcqIyjTXT3IvAABnlORHY0ah+0NeZ8LD0bYJ+JLPdFmxhZ8thivyJwDXUcZim
l/DG4qvSd+kuGWk8G/pnab4OOS+nFtWosddFoZ52MIzrYxjloMCWAzgz2Ah/lO3Z
2qsf2LKMnzDnV1GD4MjSeep4cZWY6xWyrsGK/VA8vcqLvBURZ6udeLvXaQ4hPkwa
UfdnALWx/1/zsc6q6oFEDyVmMt+0njLixY2grA1o3Lz4q6hCVgtv
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions ssl/certs/ca.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrtBFpQ4SB5QCN
/kgl3974UvUe/mcar1AEnR3rBRRdpQV4fxifDN/GBzuYt0xhfaQcPNBX8pL1luhH
sOEkS1Q1o0TsKCL+2o6x98ez0+Q0YDRCBFs027YCyBRzZB7zRwSno82A8st+XjzF
53kskXwGvv+3dv/XMc1BcO6lhVdNy65cBIhEc15Jpeq8hy27lRPIAcjldEnj5A6B
vUrCBqD1FEXobqxAYeQ8vSpqZhaa+C1p03zz0yZ4aCkUBciVoBan8dAB9oKoAL36
oSnGCTyxfXLFCGuIBqhK1dlMX/AnBy6FeCa+yAL6AsC873xevcoYEUCrcPmeFM89
BFy7vi3lAgMBAAECggEAB5ODtCkYQvIDlwBaFx+8cykX60Tu8Di9l2KGZC0ec65Z
IjK7d6MmCZMeoFOwMVoNoHhXehX4QZFl0On/WS5guhgo7aGsv6GNq9Ei1O670krP
a31NN/Uc4B0Ld/b6PaJL1IjQA8lSzNHkLRhUWrDVr+eEGYiM6+Yk6CcPRKrwSfyo
1HcX9MzEiSRwHQw3M7wRtNByjqCXxvnbtniZRAMGJl7WHONZEQNf/R+1LukLx2qK
hM89RJLj2bZ4KBC2+pPFzf8xr6oV/rLkNHj8NxwXFiSR2FuvdoLxHUS+lo48Bkw0
9hhKtnBOQY6dZetcV7HxPczyomPoAMrMkcme4Y9PkQKBgQDyHJztZCNnyyvni1+W
xnGjE9F9VpoYucDHNQihmnRE/T2R9WMAKOZb0CLeWeMKzWNLE6vQHoieDfNcjQIB
2BWaQpuHkpDMBjtjJOx3NIF34mpvJszr6ZT87IcVzlqc26QIUYX+DV6pYPjzCVN8
BEYEx9utX1erXVgLXCPmWc+mMQKBgQC1jYPaLta3croVeWiMAbUeKX8S9cZNzBZW
NaOIJWY2wGZAiJ3bjgxoiEAPaZ3rbWmC5Q9juc+6wcKxWKjmE1L9UAYr2mzkZc2v
WLXD7wK9EHArIUXZlwQgms6Flbe5RorDu79Fxq2+FsJSRNDwnNaiQcjefmawNp5S
6M4qoZDx9QKBgE2kgWrb10Lc9AqANrpqj1zF6UOxtx9AyqLXzhnNJ4ZMVCdvsz0E
4MMG33fBCb+YGESmXU4TzKorPSUsDz26J0teGvSCOy9CvF7SI4ci7nYcxRc6MTNi
qCXoUHXcxFBTW6pTQo4ziWz2LT/7eKtnz3CPC1LxJXNOLwMNnHGt0ZqxAoGAJeTe
w3iJSosAuiC4KJjmo+AHbP6toGlbtCzH8E/WENGBxjB9umjgwCTIMi9aTdxtbGvB
FZCgAhwVNg0KW9NmvAaq8xZJKjbxgorijX3itXGr5+Su/qadruyA9LL2QQ6vQgF6
/+ZjN0zqzF8euUoTJpTSh1YcuuT7kNSUy6MjbM0CgYEA8aHZbygOxyWMSQV5l+wh
Aj6Urt/LTUB9xLBwbfg6axQHb7sVY9fodB+ih0BOl1Iy0x2VQTk+jzy3R7lHBdZu
qlyePXrUzoo2BdJ5dBykzeMCjtm3QyZI1EHLHn2SCRBpIgs9Qc2cAgYCNwamAws2
lmg52kH9C1gAwNIB6KLkj/g=
-----END PRIVATE KEY-----
1 change: 1 addition & 0 deletions ssl/certs/ca.srl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
63394BC07145D7006696CBA3DA6B37DC4DB06EDF
26 changes: 26 additions & 0 deletions ssl/certs/client.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEUzCCAzsCFGM5S8BxRdcAZpbLo9prN9xNsG7fMA0GCSqGSIb3DQEBCwUAMGkx
HzAdBgNVBAMMFkFic21hY2hfU2VsZl9TaWduZWRfQ0ExEDAOBgNVBAoMB2Fic21h
Y2gxEzARBgNVBAsMCmFic21hY2hfY2ExHzAdBgkqhkiG9w0BCQEWEGluZm9AYWJz
bWFjaC5jb20wHhcNMjQwNTA3MDg1MjExWhcNMjYwNTA3MDg1MjExWjBjMRgwFgYD
VQQDDA9jb2FwLWNsaS1jbGllbnQxEDAOBgNVBAoMB2Fic21hY2gxFDASBgNVBAsM
C2Fic21hY2hfY3J0MR8wHQYJKoZIhvcNAQkBFhBpbmZvQGFic21hY2guY29tMIIC
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsO54byUb7eGxUpnjGNmzMckc
jldeC2IWLoB9KNAbpJBGfzN8jHwYkJIB7JtyFuZksPr4KhMr9IEKKWY9JcddeJlj
T5zp0QdLR/ZnPsfVSD8rtbEtCAgzO8OtoAMlTlmxDT7F+axP3ezLAjAuEP3+3UhX
1711YeciRQNcxRtQSlbiI9Y9ftgkUiysF1Sv2Dd897kE1daMBImjth8eaEmEC7iS
ayc0muVqL51J9leBRfFh67G6gvChl10iZdyT/v6EpKgUyfrG+yX0GWKHqoKBgKO4
xhGVwkMgrmk4TFBNIbqnyg3c8Ai5m3J44jYe/1M3zxlWUNuSu6ZvYEqCxUIFiruZ
PjYBIZMCyExtWAS69zh9wSl28uruDEyWRxyIHbbg2DXPnDpcCalKfrr1Zg7fKGiG
kK847oxWkXUdYjVPGwiT2E/pMoACIs8BpGAvQ5YWqbw7K5a93CDvi5TJt4b2Ej9m
ilEBQns1RSMAopd/6bWQmVMUT1hTnYmR0LzmAO7OJwpwxWtqzt8GK4zXSHuBowUx
9uORObOOQR5EO5+bycvyQvBbi+Z1y6f0OEvvBrp3ZnRbAk4ManaWzFCiaQQCvr/k
GAJt6PRKZlYMTfTfNHjd2oIuebBj0/42r6M5AbGJJj2PzxgzAS5LjdpCsW20p8bN
ZkB2egOX9A28zTyYZb0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAImOV4jTqK8j3
FD59J2ZC2rlZX1O/P5egrxVe1cfeH7OV+wGYpARsvhn1Z2IyH3rzqJrQd5j1xiLd
mh6MhFHJFWdbeCeN+//AKSVxtQoCuAq2HIe24hsQp7oDsamgKlvKTZvmsHVMwx4w
EMFoO3YodzTBmKmO78x5K5KxOyGqTXcygYgzZDad5hMaCIn93t4LHPgNs3fVJHeS
bZ8MjhE6trnyOGawhscJZrY5cF8hM5AZkEss75DzY4N5GfR6CTmKPgRj8m/GChv3
i2VF+6F7SpxofwJqtGobITcS22Qr0PH1eUBrKg8TR9v9VCB2wh/x2+OfuEbgvfHE
cxvkbUuphw==
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions ssl/certs/client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
nLIYGRGy7V3HLlv59yeXP+2NCSh9qA==
-----END PRIVATE KEY-----