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

Create self signed chain from command line #1

Merged
merged 15 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
22 changes: 11 additions & 11 deletions ca_certs/uzi_ca_certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ func GetCertPools(includeTest bool) (root *x509.CertPool, intermediate *x509.Cer
return downloadUziPool(pool)
}

func GetCerts(includeTest bool) (*[]x509.Certificate, error) {
func GetCerts(includeTest bool) ([]*x509.Certificate, error) {
pool := prepareAndCombinePools(includeTest)
return downloadUziPoolCerts(pool)
}

func GetDERs(includeTest bool) (*[][]byte, error) {
func GetDERs(includeTest bool) ([][]byte, error) {
pool := prepareAndCombinePools(includeTest)
return downloadUziPoolDERs(pool)
}
Expand All @@ -50,19 +50,19 @@ func prepareAndCombinePools(includeTest bool) UziCaPool {
return pool
}

func downloadUziPoolDERs(pool UziCaPool) (*[][]byte, error) {
func downloadUziPoolDERs(pool UziCaPool) ([][]byte, error) {
var rv = [][]byte{}
certs, err := downloadUziPoolCerts(pool)
if err != nil {
return nil, err
}
for _, cert := range *certs {
for _, cert := range certs {
rv = append(rv, cert.Raw)
}
return &rv, err
return rv, err
}

func GetTestCerts() (*[]x509.Certificate, error) {
func GetTestCerts() ([]*x509.Certificate, error) {
return downloadUziPoolCerts(TestUziCaPool)
}

Expand All @@ -81,7 +81,7 @@ func downloadUziPool(pool UziCaPool) (*x509.CertPool, *x509.CertPool, error) {
return roots, intermediates, nil
}

func downloadUziPoolCerts(pool UziCaPool) (*[]x509.Certificate, error) {
func downloadUziPoolCerts(pool UziCaPool) ([]*x509.Certificate, error) {
allUrls := append(pool.rootCaUrls, pool.intermediateCaUrls...)
all, err := downloadCerts(allUrls)
if err != nil {
Expand All @@ -103,16 +103,16 @@ func downloadPool(urls []string) (*x509.CertPool, error) {
return roots, nil
}

func downloadCerts(urls []string) (*[]x509.Certificate, error) {
certs := make([]x509.Certificate, 0)
func downloadCerts(urls []string) ([]*x509.Certificate, error) {
certs := make([]*x509.Certificate, 0)
for _, url := range urls {
certificate, err := readCertificateFromUrl(url)
if err != nil {
return nil, err
}
certs = append(certs, *certificate)
certs = append(certs, certificate)
}
return &certs, nil
return certs, nil
}

func readCertificateFromUrl(url string) (*x509.Certificate, error) {
Expand Down
26 changes: 9 additions & 17 deletions did_x509/did_x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type X509Did struct {
// DidCreator is an interface for creating a DID (Decentralized Identifier) given a chain of x509 certificates.
// The CreateDid method takes a slice of x509.Certificate and returns a DID as a string and an error if any.
type DidCreator interface {
CreateDid(chain *[]x509.Certificate) (string, error)
CreateDid(signingCert, caCert *x509.Certificate) (string, error)
}

type DidParser interface {
Expand All @@ -43,13 +43,9 @@ func NewDidParser() *DefaultDidProcessor {

// FormatDid constructs a decentralized identifier (DID) from a certificate chain and an optional policy.
// It returns the formatted DID string or an error if the root certificate or hash calculation fails.
func FormatDid(chain *[]x509.Certificate, policy string) (string, error) {
root, err := FindRootCertificate(chain)
if err != nil {
return "", err
}
func FormatDid(ca *x509.Certificate, policy string) (string, error) {
alg := "sha512"
rootHash, err := x509_cert.Hash(root.Raw, alg)
rootHash, err := x509_cert.Hash(ca.Raw, alg)
if err != nil {
return "", err
}
Expand All @@ -64,17 +60,13 @@ func FormatDid(chain *[]x509.Certificate, policy string) (string, error) {
// CreateDid generates a Decentralized Identifier (DID) from a given certificate chain.
// It extracts the Unique Registration Address (URA) from the chain, creates a policy with it, and formats the DID.
// Returns the generated DID or an error if any step fails.
func (d *DefaultDidProcessor) CreateDid(chain *[]x509.Certificate) (string, error) {
certificate, _, err := x509_cert.FindSigningCertificate(chain)
if err != nil || certificate == nil {
return "", err
}
otherNameValue, sanType, err := x509_cert.FindOtherName(certificate)
func (d *DefaultDidProcessor) CreateDid(signingCert, caCert *x509.Certificate) (string, error) {
otherNameValue, sanType, err := x509_cert.FindOtherName(signingCert)
if err != nil {
return "", err
}
policy := CreatePolicy(otherNameValue, sanType)
formattedDid, err := FormatDid(chain, policy)
formattedDid, err := FormatDid(caCert, policy)
return formattedDid, err
}
func (d *DefaultDidProcessor) ParseDid(didString string) (*X509Did, error) {
Expand Down Expand Up @@ -105,10 +97,10 @@ func CreatePolicy(otherNameValue string, sanType x509_cert.SanTypeName) string {
}

// FindRootCertificate traverses a chain of x509 certificates and returns the first certificate that is a CA.
func FindRootCertificate(chain *[]x509.Certificate) (*x509.Certificate, error) {
for _, cert := range *chain {
func FindRootCertificate(chain []*x509.Certificate) (*x509.Certificate, error) {
for _, cert := range chain {
if cert.IsCA {
return &cert, nil
return cert, nil
}
}
return nil, fmt.Errorf("cannot find root certificate")
Expand Down
46 changes: 42 additions & 4 deletions did_x509/did_x509_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 2 additions & 18 deletions did_x509/did_x509_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestDefaultDidCreator_CreateDid(t *testing.T) {
type fields struct {
}
type args struct {
chain *[]x509.Certificate
chain []*x509.Certificate
}
chain, _, rootCert, _, _, err := x509_cert.BuildCertChain("A BIG STRING")
if err != nil {
Expand All @@ -34,22 +34,6 @@ func TestDefaultDidCreator_CreateDid(t *testing.T) {
want string
errMsg string
}{
{
name: "Test case 1",
fields: fields{},
args: args{chain: &[]x509.Certificate{}},
want: "",
errMsg: "no certificates provided",
},
{
name: "Test case 2",
fields: fields{},
args: args{chain: &[]x509.Certificate{
{},
}},
want: "",
errMsg: "no certificate found in the SAN attributes, please check if the certificate is an UZI Server Certificate",
},
{
name: "Happy path",
fields: fields{},
Expand All @@ -61,7 +45,7 @@ func TestDefaultDidCreator_CreateDid(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &DefaultDidProcessor{}
got, err := d.CreateDid(tt.args.chain)
got, err := d.CreateDid(tt.args.chain[0], tt.args.chain[len(tt.args.chain)-1])
wantErr := tt.errMsg != ""
if (err != nil) != wantErr {
t.Errorf("DefaultDidProcessor.CreateDid() error = %v, errMsg %v", err, tt.errMsg)
Expand Down
55 changes: 47 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ type VC struct {
Test bool `short:"t" help:"Allow test certificates."`
}

type TestCert struct {
Identifier string `arg:"" name:"identifier" help:"Identifier for the test certificate such as an URA or UZI number."`
}

var CLI struct {
Version string `help:"Show version."`
Vc VC `cmd:"" help:"Create a new VC."`
Version string `help:"Show version."`
Vc VC `cmd:"" help:"Create a new VC."`
TestCert TestCert `cmd:"" help:"Create a new test certificate."`
}

func main() {
Expand All @@ -27,17 +32,51 @@ func main() {
if err != nil {
panic(err)
}
_, err = parser.Parse(os.Args[1:])
ctx, err := parser.Parse(os.Args[1:])
if err != nil {
parser.FatalIfErrorf(err)
}
vc := cli.Vc
jwt, err := issueVc(vc)
if err != nil {
fmt.Println(err)

switch ctx.Command() {
case "vc <certificate_file> <signing_key> <subject_did>":
vc := cli.Vc
jwt, err := issueVc(vc)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
println(jwt)
case "test-cert <identifier>":
otherName := fmt.Sprintf("2.16.528.1.1007.1.%s", cli.TestCert.Identifier)
fmt.Println("Building certificate chain for identifier:", otherName)
chain, _, _, privKey, _, err := x509_cert.BuildCertChain(cli.TestCert.Identifier)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}

chainPems, err := x509_cert.EncodeCertificates(chain...)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
signingKeyPem, err := x509_cert.EncodeRSAPrivateKey(privKey)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}

os.WriteFile("chain.pem", chainPems, 0644)
os.WriteFile("signing_key.pem", signingKeyPem, 0644)

if err != nil {
fmt.Println(err)
os.Exit(-1)
}
default:
fmt.Println("Unknown command")
os.Exit(-1)
}
println(jwt)
}

func issueVc(vc VC) (string, error) {
Expand Down
18 changes: 10 additions & 8 deletions pem/pem_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pem

import (
"encoding/pem"
"fmt"
"os"
)

Expand All @@ -20,7 +21,7 @@ func NewPemReader() *DefaultPemReader {
}

// ParseFileOrPath processes a file or directory at the given path and extracts PEM blocks of the specified pemType.
func (p *DefaultPemReader) ParseFileOrPath(path string, pemType string) (*[][]byte, error) {
func (p *DefaultPemReader) ParseFileOrPath(path string, pemType string) ([][]byte, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return nil, err
Expand All @@ -39,9 +40,9 @@ func (p *DefaultPemReader) ParseFileOrPath(path string, pemType string) (*[][]by
if err != nil {
return nil, err
}
files = append(files, *blocks...)
files = append(files, blocks...)
}
return &files, nil
return files, nil
} else {
blocks, err := readFile(path, pemType)
return blocks, err
Expand All @@ -50,21 +51,22 @@ func (p *DefaultPemReader) ParseFileOrPath(path string, pemType string) (*[][]by
}

// readFile reads a file from the given filename, parses it for PEM blocks of the specified type, and returns the blocks.
func readFile(filename string, pemType string) (*[][]byte, error) {
func readFile(filename string, pemType string) ([][]byte, error) {
fmt.Println("filename: ", filename)
files := make([][]byte, 0)
content, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
if looksLineCert(content, pemType) {
foundBlocks := ParsePemBlocks(content, pemType)
files = append(files, *foundBlocks...)
files = append(files, foundBlocks...)
}
return &files, nil
return files, nil
}

// ParsePemBlocks extracts specified PEM blocks from the provided certificate bytes and returns them as a pointer to a slice of byte slices.
func ParsePemBlocks(cert []byte, pemType string) *[][]byte {
func ParsePemBlocks(cert []byte, pemType string) [][]byte {
blocks := make([][]byte, 0)
for {
pemBlock, tail := pem.Decode(cert)
Expand All @@ -80,7 +82,7 @@ func ParsePemBlocks(cert []byte, pemType string) *[][]byte {
cert = tail

}
return &blocks
return blocks
}

// looksLineCert checks if the given certificate data is a valid PEM block of the specified type.
Expand Down
Loading