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

Cira #133

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
# Config
.env
.DS_store
#certs
**/*.pem
**/*.crt
**/*.key

# Binaries for programs and plugins
*.exe
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ FROM golang:1.23-alpine3.20@sha256:9dd2625a1ff2859b8d8b01d8f7822c0f528942fe56cfe
COPY --from=modules /go/pkg /go/pkg
COPY . /app
WORKDIR /app
RUN go mod tidy
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -o /bin/app ./cmd/app

RUN mkdir -p /.config/device-management-toolkit
# Step 3: Final
FROM scratch
COPY --from=builder /app/config /config
COPY --from=builder /app/internal/app/migrations /migrations
COPY --from=builder /bin/app /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /.config/device-management-toolkit /.config/device-management-toolkit
CMD ["/app"]
6 changes: 6 additions & 0 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ func main() {
log.Fatalf("App init error: %s", err)
}

// root, privateKey, err := certificates.GenerateRootCertificate(true, cfg.CommonName, "US", "open-amt-cloud-toolkit", true)
// if err != nil {
// log.Fatalf("Error generating root certificate: %s", err)
// }
// certificates.IssueWebServerCertificate(certificates.CertAndKeyType{Cert: root, Key: privateKey}, false, cfg.CommonName, "US", "open-amt-cloud-toolkit", true)

if os.Getenv("GIN_MODE") != "debug" {
go func() {
browserError := openBrowser("http://localhost:"+cfg.HTTP.Port, runtime.GOOS)
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type (
Name string `env-required:"true" yaml:"name" env:"APP_NAME"`
Repo string `env-required:"true" yaml:"repo" env:"APP_REPO"`
Version string `env-required:"true"`
CommonName string `env-required:"true" yaml:"common_name" env:"APP_COMMON_NAME"`
EncryptionKey string `yaml:"encryption_key" env:"APP_ENCRYPTION_KEY"`
}

Expand Down Expand Up @@ -51,6 +52,7 @@ func NewConfig() (*Config, error) {
Name: "console",
Repo: "open-amt-cloud-toolkit/console",
Version: "DEVELOPMENT",
CommonName: "localhost",
EncryptionKey: "",
},
HTTP: HTTP{
Expand Down
33 changes: 17 additions & 16 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
services:
postgres:
container_name: postgres
image: postgres
networks:
- openamtnetwork1
volumes:
- pg-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: "postgresadmin"
POSTGRES_PASSWORD: "admin123"
POSTGRES_DB: "rpsdb"
ports:
- 5432:5432
# postgres:
# container_name: postgres
# image: postgres
# networks:
# - openamtnetwork1
# volumes:
# - pg-data:/var/lib/postgresql/data
# environment:
# POSTGRES_USER: "postgresadmin"
# POSTGRES_PASSWORD: "admin123"
# POSTGRES_DB: "rpsdb"
# ports:
# - 5432:5432
app:
build: .
container_name: app
Expand All @@ -24,11 +24,12 @@ services:
APP_ENCRYPTION_KEY: "Jf3Q2nXJ+GZzN1dbVQms0wbB4+i/5PjL" # This is a test encryption key for the app
HTTP_HOST: ""
GIN_MODE: "debug"
DB_URL: "postgres://postgresadmin:admin123@postgres:5432/rpsdb"
#DB_URL: "postgres://postgresadmin:admin123@postgres:5432/rpsdb"
ports:
- 8181:8181
depends_on:
- postgres
- 4433:4433
# depends_on:
# - postgres
# integration:
# build:
# context: .
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.22.0

toolchain go1.23.1

// replace github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 => ../go-wsman-messages
replace github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 => ../go-wsman-messages

require (
github.com/Masterminds/squirrel v1.5.4
Expand Down
13 changes: 13 additions & 0 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/open-amt-cloud-toolkit/console/config"
consolehttp "github.com/open-amt-cloud-toolkit/console/internal/controller/http"
"github.com/open-amt-cloud-toolkit/console/internal/controller/tcp/cira"
wsv1 "github.com/open-amt-cloud-toolkit/console/internal/controller/ws/v1"
"github.com/open-amt-cloud-toolkit/console/internal/usecase"
"github.com/open-amt-cloud-toolkit/console/pkg/db"
Expand Down Expand Up @@ -64,6 +65,12 @@ func Run(cfg *config.Config) {
}

wsv1.RegisterRoutes(handler, log, usecases.Devices, upgrader)

ciraServer, err := cira.NewServer("config/cert.pem", "config/key.pem")
if err != nil {
log.Fatal("CIRA Server failed: %v", err)
}

httpServer := httpserver.New(handler, httpserver.Port(cfg.HTTP.Host, cfg.HTTP.Port))

// Waiting signal
Expand All @@ -75,11 +82,17 @@ func Run(cfg *config.Config) {
log.Info("app - Run - signal: " + s.String())
case err = <-httpServer.Notify():
log.Error(fmt.Errorf("app - Run - httpServer.Notify: %w", err))
case ciraErr := <-ciraServer.Notify():
log.Error(fmt.Errorf("app - Run - ciraServer.Notify: %w", ciraErr))
}

// Shutdown
err = httpServer.Shutdown()
if err != nil {
log.Error(fmt.Errorf("app - Run - httpServer.Shutdown: %w", err))
}
err = ciraServer.Shutdown()
if err != nil {
log.Error(fmt.Errorf("app - Run - ciraServer.Shutdown: %w", err))
}
}
206 changes: 206 additions & 0 deletions internal/certificates/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package certificates

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net/url"
"os"
"time"
)

func GenerateRootCertificate(addThumbPrintToName bool, commonName, country, organization string, strong bool) (*x509.Certificate, *rsa.PrivateKey, error) {
keyLength := 2048
if strong {
keyLength = 3072
}

// Generate RSA keys
privateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return nil, nil, err
}

// Preparing the certificate
var maxValue uint = 128

serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), maxValue))
if err != nil {
return nil, nil, err
}

thirtyYears := 30

if addThumbPrintToName {
hash := sha256.New()
hash.Write(privateKey.PublicKey.N.Bytes()) // Simplified approach to get a thumbprint-like result
commonName += "-" + fmt.Sprintf("%x", hash.Sum(nil)[:3])
}

if country == "" {
country = "unknown country"
}

if organization == "" {
organization = "unknown organization"
}

template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{organization},
Country: []string{country},
},
NotBefore: time.Now().AddDate(-1, 0, 0),
NotAfter: time.Now().AddDate(thirtyYears, 0, 0),

KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
IsCA: true,
}

// Create a self-signed certificate
certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
if err != nil {
return nil, nil, err
}

// Encoding certificate to PEM format
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})

// Save to files (optional)
certOut, err := os.Create("root_cert.pem")
if err != nil {
return nil, nil, err
}

_, err = certOut.Write(certPEM)
if err != nil {
return nil, nil, err
}

certOut.Close()

keyOut, err := os.Create("root_key.pem")
if err != nil {
return nil, nil, err
}

err = pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
if err != nil {
return nil, nil, err
}

keyOut.Close()

return &template, privateKey, nil
}

type CertAndKeyType struct {
Cert *x509.Certificate
Key *rsa.PrivateKey
}

func IssueWebServerCertificate(rootCert CertAndKeyType, addThumbPrintToName bool, commonName, country, organization string, strong bool) (*x509.Certificate, *rsa.PrivateKey, error) {
keyLength := 2048
if strong {
keyLength = 3072
}

// Generate RSA keys
keys, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return nil, nil, err
}

var maxValue uint = 128

serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), maxValue))
if err != nil {
return nil, nil, err
}

thirtyYears := 30
notBefore := time.Now().AddDate(-1, 0, 0)
notAfter := time.Now().AddDate(thirtyYears, 0, 0)

subject := pkix.Name{
CommonName: commonName,
}

if country != "" {
subject.Country = []string{country}
}

if organization != "" {
subject.Organization = []string{organization}
}

if addThumbPrintToName {
hash := sha256.New()
hash.Write(keys.PublicKey.N.Bytes()) // Simplified approach to get a thumbprint-like result
subject.CommonName += "-" + string(hash.Sum(nil)[:3])
}

hash := sha256.Sum256(keys.PublicKey.N.Bytes())

template := x509.Certificate{
SerialNumber: serialNumber,
Subject: subject,
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign | x509.KeyUsageDataEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: false,
SubjectKeyId: hash[:],
}

// Subject Alternative Name
uri, _ := url.Parse("http://" + commonName + "/")
template.DNSNames = []string{commonName, "localhost"}
template.URIs = []*url.URL{uri}

// Sign the certificate with root certificate private key
certBytes, err := x509.CreateCertificate(rand.Reader, &template, rootCert.Cert, &keys.PublicKey, rootCert.Key)
if err != nil {
return nil, nil, err
}

// Encoding certificate to PEM format
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})

// Save to files (optional)
certOut, err := os.Create(commonName + "_cert.pem")
if err != nil {
return nil, nil, err
}

_, err = certOut.Write(certPEM)
if err != nil {
return nil, nil, err
}

certOut.Close()

keyOut, err := os.Create(commonName + "_key.pem")
if err != nil {
return nil, nil, err
}

err = pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(keys)})
if err != nil {
return nil, nil, err
}

keyOut.Close()

return &template, keys, nil
}
Loading
Loading