Skip to content

NOISSUE - Add DTLS config to coap-cli#11

Merged
dborovcanin merged 12 commits intoabsmach:mainfrom
felixgateru:NOISSUE-configfile
Sep 5, 2025
Merged

NOISSUE - Add DTLS config to coap-cli#11
dborovcanin merged 12 commits intoabsmach:mainfrom
felixgateru:NOISSUE-configfile

Conversation

@felixgateru
Copy link
Contributor

@felixgateru felixgateru commented May 7, 2024

What type of PR is this?

This is a feature because it adds dtls capability to the coap client of the coap cli.

What does this do?

This pr:

  • Adds dtls configuration by adding certs and relevant dtls config settings from pion/dtls library

Which issue(s) does this PR fix/relate to?

Have you included tests for your changes?

No,

Did you document any new/modified feature?

No,

Notes

To be merged after #8

@rodneyosodo rodneyosodo requested review from WashingtonKK and nyagamunene and removed request for nyagamunene May 22, 2024 10:05
@felixgateru felixgateru force-pushed the NOISSUE-configfile branch 2 times, most recently from e073ad7 to 47cf8d4 Compare May 24, 2024 09:43
@felixgateru felixgateru marked this pull request as ready for review May 24, 2024 09:48
@arvindh123 arvindh123 moved this from 🩺 Review and testing to 🛑 Blocked in SuperMQ Mar 11, 2025
@rodneyosodo
Copy link
Contributor

rodneyosodo commented Sep 5, 2025

The Server Example I have used

package main

import (
	"bytes"
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"log"
	"math/big"
	"os"
	"time"

	piondtls "github.com/pion/dtls/v3"
	"github.com/plgd-dev/go-coap/v3/dtls"
	"github.com/plgd-dev/go-coap/v3/examples/dtls/pki"
	"github.com/plgd-dev/go-coap/v3/message"
	"github.com/plgd-dev/go-coap/v3/message/codes"
	"github.com/plgd-dev/go-coap/v3/mux"
	"github.com/plgd-dev/go-coap/v3/net"
	"github.com/plgd-dev/go-coap/v3/options"
	"github.com/plgd-dev/go-coap/v3/udp/client"
)

func onNewConn(cc *client.Conn) {
	dtlsConn, ok := cc.NetConn().(*piondtls.Conn)
	if !ok {
		log.Fatalf("invalid type %T", cc.NetConn())
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	// force handshake otherwhise ConnectionState is not available
	err := dtlsConn.HandshakeContext(ctx)
	if err != nil {
		log.Fatalf("handshake failed: %v", err)
	}
	state, ok := dtlsConn.ConnectionState()
	if !ok {
		log.Fatalf("cannot get connection state")
	}
	clientCert, err := x509.ParseCertificate(state.PeerCertificates[0])
	if err != nil {
		log.Fatal(err)
	}
	cc.SetContextValue("client-cert", clientCert)
	cc.AddOnClose(func() {
		log.Println("closed connection")
	})
}

func toHexInt(n *big.Int) string {
	return fmt.Sprintf("%x", n) // or %X or upper case
}

func handleA(w mux.ResponseWriter, r *mux.Message) {
	clientCert := r.Context().Value("client-cert").(*x509.Certificate)
	log.Println("Serial number:", toHexInt(clientCert.SerialNumber))
	log.Println("Subject:", clientCert.Subject)
	log.Println("Email:", clientCert.EmailAddresses)

	log.Printf("got message in handleA:  %+v from %v", r, w.Conn().RemoteAddr())
	err := w.SetResponse(codes.GET, message.TextPlain, bytes.NewReader([]byte("A hello world")))
	if err != nil {
		log.Printf("cannot set response: %v", err)
	}
}

func main() {
	m := mux.NewRouter()
	m.Handle("/a", mux.HandlerFunc(handleA))

	config, err := createServerConfig()
	if err != nil {
		log.Fatalln(err)
		return
	}
	fmt.Println("Server config created")

	log.Fatal(listenAndServeDTLS("udp", ":5688", config, m))
}

func listenAndServeDTLS(network string, addr string, config *piondtls.Config, handler mux.Handler) error {
	l, err := net.NewDTLSListener(network, addr, config)
	if err != nil {
		return err
	}
	defer l.Close()
	s := dtls.NewServer(options.WithMux(handler), options.WithOnNewConn(onNewConn))
	return s.Serve(l)
}

func createServerConfig() (*piondtls.Config, error) {
	// root cert
	ca, rootBytes, _, caPriv, err := pki.GenerateCA()
	if err != nil {
		return nil, err
	}
	// server cert
	certBytes, keyBytes, err := pki.GenerateCertificate(ca, caPriv, "server@test.com")
	if err != nil {
		return nil, err
	}
	certificate, err := pki.LoadKeyAndCertificate(keyBytes, certBytes)
	if err != nil {
		return nil, err
	}
	// cert pool
	certPool, err := pki.LoadCertPool(rootBytes)
	if err != nil {
		return nil, err
	}

	// client cert
	clientCertBytes, clientKeyBytes, err := pki.GenerateCertificate(ca, caPriv, "client@test.com")
	if err != nil {
		return nil, err
	}

	// save certs to files
	if err := os.WriteFile("ca.crt", rootBytes, 0644); err != nil {
		return nil, err
	}
	if err := os.WriteFile("client.crt", clientCertBytes, 0644); err != nil {
		return nil, err
	}
	if err := os.WriteFile("client.key", clientKeyBytes, 0644); err != nil {
		return nil, err
	}

	return &piondtls.Config{
		Certificates:         []tls.Certificate{*certificate},
		ExtendedMasterSecret: piondtls.RequireExtendedMasterSecret,
		ClientCAs:            certPool,
		ClientAuth:           piondtls.RequireAndVerifyClientCert,
	}, nil
}
go run ./example/main.go
make all
./build/coap-cli-linux get /a -H localhost -p 5688 -C client.crt -K client.key -A ca.crt

@rodneyosodo rodneyosodo changed the base branch from master to main September 5, 2025 12:15
Copy link
Contributor

@rodneyosodo rodneyosodo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-project-automation github-project-automation bot moved this from 🛑 Blocked to 🚀 Ready for merge in SuperMQ Sep 5, 2025
@dborovcanin dborovcanin merged commit e0f7b32 into absmach:main Sep 5, 2025
1 check passed
@github-project-automation github-project-automation bot moved this from 🚀 Ready for merge to ✅ Done in SuperMQ Sep 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants