-
Notifications
You must be signed in to change notification settings - Fork 14
NOISSUE - Add dtls config to CoAP cli #7
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
Changes from 4 commits
5df4ce5
714f7ed
bff96bb
caff800
0ca3972
56c3462
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,11 +15,13 @@ When running, please provide following format: | |
| | p | port | "5683" | | ||
| | d | data to be sent in POST or PUT | "" | | ||
| | cf | content format | 50 (JSON format) | | ||
| |tls | dtls support | false | | ||
|
|
||
| The dtls configuration currently supports PKI certificates. Place the relevant certificates in the certs folder before building. | ||
| ## Examples: | ||
|
|
||
| ```bash | ||
| coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -o | ||
| coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -o -tls | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add seperate example for dtls |
||
| ``` | ||
| ```bash | ||
| coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| package cert_utility | ||
|
||
|
|
||
| import ( | ||
| "context" | ||
| "crypto" | ||
| "crypto/ecdsa" | ||
| "crypto/rsa" | ||
| "crypto/tls" | ||
| "crypto/x509" | ||
| "encoding/pem" | ||
| "errors" | ||
| "log" | ||
| "os" | ||
| "strings" | ||
|
|
||
| piondtls "github.com/pion/dtls/v2" | ||
| ) | ||
|
|
||
| // Create pion dtls config from certificates. | ||
| func CreateClientConfig(ctx context.Context) (*piondtls.Config, error) { | ||
| clientKeyBytes := make([]byte, 2048) | ||
| clientCrtBytes := make([]byte, 2048) | ||
| caBytes := make([]byte, 2048) | ||
|
|
||
| kb, err := os.Open("../certs/client.key") | ||
|
||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| defer kb.Close() | ||
| kb.Read(clientKeyBytes) | ||
|
||
|
|
||
| cb, err := os.Open("../certs/client.crt") | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| defer cb.Close() | ||
| cb.Read(clientCrtBytes) | ||
|
|
||
| cab, err := os.Open("../certs/ca.crt") | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| defer cab.Close() | ||
| cab.Read(caBytes) | ||
|
|
||
| certificate, err := LoadKeyAndCertificate(clientKeyBytes, clientCrtBytes) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // cert pool | ||
| certPool, err := LoadCertPool(caBytes) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &piondtls.Config{ | ||
| Certificates: []tls.Certificate{*certificate}, | ||
| ExtendedMasterSecret: piondtls.RequireExtendedMasterSecret, | ||
| RootCAs: certPool, | ||
| InsecureSkipVerify: true, | ||
| }, nil | ||
| } | ||
|
|
||
| func LoadCertificate(certBytes []byte) (*tls.Certificate, error) { | ||
| var certificate tls.Certificate | ||
|
|
||
| for { | ||
| block, rest := pem.Decode(certBytes) | ||
| if block == nil { | ||
| break | ||
| } | ||
|
|
||
| if block.Type != "CERTIFICATE" { | ||
| return nil, errors.New("block is not a certificate, unable to load certificates") | ||
| } | ||
|
|
||
| certificate.Certificate = append(certificate.Certificate, block.Bytes) | ||
| certBytes = rest | ||
| } | ||
|
|
||
| if len(certificate.Certificate) == 0 { | ||
| return nil, errors.New("no certificate found, unable to load certificates") | ||
| } | ||
|
|
||
| return &certificate, nil | ||
| } | ||
|
|
||
| func LoadKey(keyBytes []byte) (crypto.PrivateKey, error) { | ||
| block, _ := pem.Decode(keyBytes) | ||
| if block == nil || !strings.HasSuffix(block.Type, "PRIVATE KEY") { | ||
| return nil, errors.New("block is not a private key, unable to load key") | ||
| } | ||
|
|
||
| if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil { | ||
| return key, nil | ||
| } | ||
|
|
||
| if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { | ||
| switch key := key.(type) { | ||
| case *rsa.PrivateKey, *ecdsa.PrivateKey: | ||
| return key, nil | ||
| default: | ||
| return nil, errors.New("unknown key time in PKCS#8 wrapping, unable to load key") | ||
| } | ||
| } | ||
|
|
||
| if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil { | ||
| return key, nil | ||
| } | ||
|
|
||
| return nil, errors.New("no private key found, unable to load key") | ||
| } | ||
|
|
||
| // LoadKeyAndCertificate loads client certificate | ||
| func LoadKeyAndCertificate(keyBytes []byte, certBytes []byte) (*tls.Certificate, error) { | ||
| certificate, err := LoadCertificate(certBytes) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| key, err := LoadKey(keyBytes) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| certificate.PrivateKey = key | ||
| return certificate, nil | ||
| } | ||
|
|
||
| // LoadCertPool loads cert pool from ca certificate | ||
| func LoadCertPool(caBytes []byte) (*x509.CertPool, error) { | ||
| rootCertificate, err := LoadCertificate(caBytes) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| certPool := x509.NewCertPool() | ||
| for _, certBytes := range rootCertificate.Certificate { | ||
| cert, err := x509.ParseCertificate(certBytes) | ||
| if err != nil { | ||
| certPool = nil | ||
| return nil, err | ||
| } | ||
| certPool.AddCert(cert) | ||
| } | ||
|
|
||
| return certPool, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| ^ | ||
| -----END CERTIFICATE----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| ^ | ||
| -----END CERTIFICATE----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| ^ | ||
| -----END CERTIFICATE----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,11 @@ import ( | |
| "syscall" | ||
|
|
||
| coap "github.com/mainflux/coap-cli/coap" | ||
| "github.com/plgd-dev/go-coap/v2/message" | ||
| coapmsg "github.com/plgd-dev/go-coap/v2/message" | ||
| "github.com/plgd-dev/go-coap/v2/message/codes" | ||
| "github.com/plgd-dev/go-coap/v2/udp/message/pool" | ||
|
|
||
| "github.com/plgd-dev/go-coap/v3/message" | ||
| 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" | ||
| ) | ||
|
|
||
| const ( | ||
|
|
@@ -36,9 +37,10 @@ mathod: get, put, post or delete | |
| -p port (default: "5683") | ||
| -d data to be sent in POST or PUT (default: "") | ||
| -cf content format (default: 50 - JSON format)) | ||
|
|
||
| -tls use DTLS (default: false) | ||
| The current implementation of DTLS uses PKI certificates. Please generate certificates and place them in certs folder. | ||
| Examples: | ||
| coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -o | ||
| coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -o -tls | ||
| coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" | ||
| coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth 1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" -h 0.0.0.0 -p 1234 | ||
| ` | ||
|
|
@@ -55,7 +57,7 @@ func parseCode(code string) (codes.Code, error) { | |
| case delete: | ||
| return codes.DELETE, nil | ||
| } | ||
| return 0, errors.New("Message can be GET, POST, PUT or DELETE") | ||
| return 0, errors.New("MESSAGE CAN BE GET, POST, PUT OR DELETE") | ||
| } | ||
|
|
||
| func printMsg(m *pool.Message) { | ||
|
|
@@ -70,7 +72,7 @@ func main() { | |
| } | ||
| help := strings.ToLower(os.Args[1]) | ||
| if help == "-h" || help == "--help" { | ||
| log.Println(helpMsg) | ||
| log.Print(helpMsg) | ||
| os.Exit(0) | ||
| } | ||
|
|
||
|
|
@@ -95,9 +97,10 @@ func main() { | |
| cf := flag.Int("cf", 50, "Content format") | ||
| d := flag.String("d", "", "Message data") | ||
| a := flag.String("auth", "", "Auth token") | ||
| s := flag.Bool("tls", false, "Use DTLS") | ||
| flag.Parse() | ||
|
|
||
| client, err := coap.New(*h + ":" + *p) | ||
| client, err := coap.New(*h+":"+*p, *s) | ||
| if err != nil { | ||
| log.Fatal("Error creating client: ", err) | ||
| } | ||
|
|
@@ -123,9 +126,10 @@ func main() { | |
| if err != nil { | ||
| log.Fatal("Error observing resource: ", err) | ||
| } | ||
| errs := make(chan error, 2) | ||
| errs := make(chan error, 1) // make the channel buffered | ||
|
||
|
|
||
| go func() { | ||
| c := make(chan os.Signal) | ||
| c := make(chan os.Signal, 1) // make the channel buffered | ||
|
||
| signal.Notify(c, syscall.SIGINT) | ||
| errs <- fmt.Errorf("%s", <-c) | ||
| }() | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,26 +8,41 @@ import ( | |||||||||||
| "log" | ||||||||||||
| "time" | ||||||||||||
|
|
||||||||||||
| "github.com/plgd-dev/go-coap/v2/message" | ||||||||||||
| "github.com/plgd-dev/go-coap/v2/message/codes" | ||||||||||||
| "github.com/plgd-dev/go-coap/v2/udp" | ||||||||||||
| "github.com/plgd-dev/go-coap/v2/udp/client" | ||||||||||||
| "github.com/plgd-dev/go-coap/v2/udp/message/pool" | ||||||||||||
| cert_utility "github.com/mainflux/coap-cli/cert_utility" | ||||||||||||
|
||||||||||||
|
|
||||||||||||
| "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" | ||||||||||||
| "github.com/plgd-dev/go-coap/v3/udp" | ||||||||||||
| "github.com/plgd-dev/go-coap/v3/udp/client" | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| // Client represents CoAP client. | ||||||||||||
| type Client struct { | ||||||||||||
| conn *client.ClientConn | ||||||||||||
| conn *client.Conn | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // New returns new CoAP client connecting it to the server. | ||||||||||||
| func New(addr string) (Client, error) { | ||||||||||||
| c, err := udp.Dial(addr) | ||||||||||||
| if err != nil { | ||||||||||||
| log.Fatalf("Error dialing: %v", err) | ||||||||||||
| func New(addr string, to_dtls bool) (Client, error) { | ||||||||||||
|
||||||||||||
| if !to_dtls { // UDP | ||||||||||||
| c, err := udp.Dial(addr) | ||||||||||||
| if err != nil { | ||||||||||||
| log.Fatalf("Error dialing: %v", err) | ||||||||||||
| } | ||||||||||||
| return Client{conn: c}, nil | ||||||||||||
| } else { // DTLS | ||||||||||||
| config, err := cert_utility.CreateClientConfig(context.Background()) | ||||||||||||
| if err != nil { | ||||||||||||
| log.Fatalln(err) | ||||||||||||
| } | ||||||||||||
| co, err := dtls.Dial("localhost:5688", config) | ||||||||||||
| if err != nil { | ||||||||||||
| log.Fatalf("Error dialing: %v", err) | ||||||||||||
| } | ||||||||||||
| return Client{conn: co}, err | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return Client{conn: c}, nil | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Send send a message. | ||||||||||||
|
|
@@ -45,11 +60,14 @@ func (c Client) Send(path string, msgCode codes.Code, cf message.MediaType, payl | |||||||||||
| case codes.DELETE: | ||||||||||||
| return c.conn.Delete(ctx, path, opts...) | ||||||||||||
| } | ||||||||||||
| return nil, errors.New("Invalid message code") | ||||||||||||
| return nil, errors.New("INVALID MESSAGE CODE") | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Receive receives a message. | ||||||||||||
| func (c Client) Receive(path string, opts ...message.Option) (*client.Observation, error) { | ||||||||||||
| func (c Client) Receive(path string, opts ...message.Option) (interface { | ||||||||||||
|
||||||||||||
| Cancel(ctx context.Context, opts ...message.Option) error | ||||||||||||
| Canceled() bool | ||||||||||||
| }, error) { | ||||||||||||
|
||||||||||||
| func (c Client) Receive(path string, opts ...message.Option) (interface { | |
| Cancel(ctx context.Context, opts ...message.Option) error | |
| Canceled() bool | |
| }, error) { | |
| func (c Client) Receive(path string, opts ...message.Option) (client.Observation, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think the Conn type has an implementation of Observation.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,22 @@ | ||
| module github.com/mainflux/coap-cli | ||
|
|
||
| go 1.15 | ||
| go 1.21 | ||
|
|
||
| require ( | ||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect | ||
| github.com/plgd-dev/go-coap/v2 v2.4.0 | ||
| golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect | ||
| golang.org/x/sys v0.0.0-20201013081832-0aaa2718063a // indirect | ||
| gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect | ||
| gopkg.in/yaml.v2 v2.3.0 // indirect | ||
| github.com/pion/dtls/v2 v2.2.8-0.20230905141523-2b584af66577 | ||
| github.com/plgd-dev/go-coap/v3 v3.1.5 | ||
| ) | ||
|
|
||
| require ( | ||
| 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/pion/logging v0.2.2 // indirect | ||
| github.com/pion/transport/v3 v3.0.1 // indirect | ||
| go.uber.org/atomic v1.11.0 // indirect | ||
| golang.org/x/crypto v0.13.0 // indirect | ||
| golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect | ||
| golang.org/x/net v0.15.0 // indirect | ||
| golang.org/x/sync v0.3.0 // indirect | ||
| golang.org/x/sys v0.12.0 // indirect | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
align