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

Adopt TrustAnchorIdentifiers from v03 of MTC draft #5

Merged
merged 6 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: '1.23'

Expand Down
32 changes: 13 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ For every batch, the CA signs that root together with all the roots
Let's create an MTC CA.

```
$ mtc ca new --batch-duration 5m --lifetime 1h my-mtc-ca ca.example.com/path
$ mtc ca new --batch-duration 5m --lifetime 1h 62253.12.15 ca.example.com/path
```

This creates a new MTC CA called `my-mtc-ca`, and puts the data in the
Expand Down Expand Up @@ -137,7 +137,7 @@ is `ca-params`, which contains the information about the CA:

```
$ mtc inspect ca-params www/mtc/v1/ca-params
issuer_id my-mtc-ca
issuer 62253.12.15
start_time 1705677477 2024-01-19 16:17:57 +0100 CET
batch_duration 300 5m0s
life_time 3600 1h0m0s
Expand Down Expand Up @@ -356,33 +356,27 @@ tree_heads[2] ab3cb1262fc084be0447c2b3d175d63f6ec2782dcc1443888b12f685976093d5

### Creating a certificate

In MTC, a **certificate** is an assertion, together with the batch number,
`issuer_id` of the CA, and an authentication path in the Merkle tree.
In MTC, a **certificate** is an assertion,
together with the TrustAnchorIdentifier (consisting of an OID for the CA and the batch number),
and an authentication path in the Merkle tree.
Let's create one for our initial assertion.

```
$ mtc ca cert -i my-assertion -o my-cert
$ mtc inspect cert my-cert
```

If we inspect the certificate, it can recompute the root from the authentication path and CA parameters:

```
$ mtc inspect -ca-params www/mtc/v1/ca-params cert my-cert
subject_type TLS
signature_scheme p256
public_key_hash a02a1758e4c9d6511dc02f59301b9f29e41762d3d769c87a22333497984a41ef
dns [example.com]
ip4 [198.51.100.60]

proof_type merkle_tree_sha256
issuer_id my-mtc-ca
batch 0
index 0
authentication path
00b17df8d909fd3e77005486a16ca00fdc9af38f92a23351359fd420d9f2ef78
```

If we provide the `ca-params` to `mtc inspect`, it can recompute the root
from the authentication path:

```
$ mtc inspect -ca-params www/mtc/v1/ca-params cert my-cert
[…]
proof_type merkle_tree_sha256
CA OID 62253.12.15
batch 0
index 0
recomputed root c005dcdb53c4e41befcf3a294b815d8b8aa0a260e9f10bfd4e4cb52eb3724aa3
Expand Down
6 changes: 3 additions & 3 deletions ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
)

type NewOpts struct {
IssuerId string
Issuer mtc.RelativeOID
HttpServer string

// Fields below are optional.
Expand Down Expand Up @@ -991,7 +991,7 @@ func (h *Handle) issueBatchTo(dir string, batch mtc.Batch, empty bool) error {
return nil
}

// Creates a new Merkle Tree CA, and opens it.
// New creates a new Merkle Tree CA, and opens it.
//
// Call Handle.Close() when done.
func New(path string, opts NewOpts) (*Handle, error) {
Expand Down Expand Up @@ -1034,7 +1034,7 @@ func New(path string, opts NewOpts) (*Handle, error) {
h.params.StartTime = uint64(time.Now().Unix())

h.params.HttpServer = opts.HttpServer
h.params.IssuerId = opts.IssuerId
h.params.Issuer = opts.Issuer

if opts.SignatureScheme == 0 {
opts.SignatureScheme = mtc.TLSDilitihium5r3
Expand Down
90 changes: 50 additions & 40 deletions cmd/mtc/main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package main

import (
"errors"
"github.com/bwesterb/mtc"
"github.com/bwesterb/mtc/ca"

"github.com/urfave/cli/v2"
"golang.org/x/crypto/cryptobyte"

"bufio"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"net"
Expand Down Expand Up @@ -400,10 +399,18 @@ func handleCaNew(cc *cli.Context) error {
cli.ShowSubcommandHelp(cc)
return errArgs
}

taiString := cc.Args().Get(0)
oid := mtc.RelativeOID{}
err := oid.UnmarshalText([]byte(taiString))
if err != nil {
return err
}

h, err := ca.New(
cc.String("ca-path"),
ca.NewOpts{
IssuerId: cc.Args().Get(0),
Issuer: oid,
HttpServer: cc.Args().Get(1),

BatchDuration: cc.Duration("batch-duration"),
Expand Down Expand Up @@ -575,23 +582,28 @@ func handleInspectCert(cc *cli.Context) error {
if err != nil {
return err
}
params, err := inspectGetCAParams(cc)
if err != nil {
return err
}

caStore := mtc.LocalCAStore{}
caStore.Add(*params)

var c mtc.BikeshedCertificate
err = c.UnmarshalBinary(buf)
err = c.UnmarshalBinary(buf, &caStore)
if err != nil {
return err
}

w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
writeAssertion(w, c.Assertion)
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "proof_type\t%v\n", c.Proof.TrustAnchor().ProofType())
tai := c.Proof.TrustAnchorIdentifier()
fmt.Fprintf(w, "proof_type\t%v\n", tai.ProofType(&caStore))

switch anch := c.Proof.TrustAnchor().(type) {
case *mtc.MerkleTreeTrustAnchor:
fmt.Fprintf(w, "issuer_id\t%s\n", anch.IssuerId())
fmt.Fprintf(w, "batch\t%d\n", anch.BatchNumber())
}
fmt.Fprintf(w, "CA OID\t%s\n", tai.Issuer)
fmt.Fprintf(w, "Batch number\t%d\n", tai.BatchNumber)

switch proof := c.Proof.(type) {
case *mtc.MerkleTreeProof:
Expand All @@ -601,38 +613,30 @@ func handleInspectCert(cc *cli.Context) error {
switch proof := c.Proof.(type) {
case *mtc.MerkleTreeProof:
path := proof.Path()
batch := &mtc.Batch{
CA: params,
Number: tai.BatchNumber,
}

params, err := inspectGetCAParams(cc)
if err == nil {
anch := proof.TrustAnchor().(*mtc.MerkleTreeTrustAnchor)

batch := &mtc.Batch{
CA: params,
Number: anch.BatchNumber(),
}

if anch.IssuerId() != params.IssuerId {
return fmt.Errorf(
"IssuerId doesn't match: %s ≠ %s",
params.IssuerId,
anch.IssuerId(),
)
}
aa := c.Assertion.Abridge()
root, err := batch.ComputeRootFromAuthenticationPath(
proof.Index(),
path,
&aa,
if !tai.Issuer.Equal(&params.Issuer) {
return fmt.Errorf(
"IssuerId doesn't match: %s ≠ %s",
params.Issuer,
tai.Issuer,
)
if err != nil {
return fmt.Errorf("computing root: %w", err)
}

fmt.Fprintf(w, "recomputed root\t%x\n", root)
} else if err != errNoCaParams {
return err
}
aa := c.Assertion.Abridge()
root, err := batch.ComputeRootFromAuthenticationPath(
proof.Index(),
path,
&aa,
)
if err != nil {
return fmt.Errorf("computing root: %w", err)
}

fmt.Fprintf(w, "recomputed root\t%x\n", root)

w.Flush()
fmt.Printf("authentication path\n")
for i := 0; i < len(path)/mtc.HashLen; i++ {
Expand Down Expand Up @@ -721,7 +725,7 @@ func handleInspectCaParams(cc *cli.Context) error {
return err
}
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
fmt.Fprintf(w, "issuer_id\t%s\n", p.IssuerId)
fmt.Fprintf(w, "issuer\t%s\n", p.Issuer)
fmt.Fprintf(w, "start_time\t%d\t%s\n", p.StartTime,
time.Unix(int64(p.StartTime), 0))
fmt.Fprintf(w, "batch_duration\t%d\t%s\n", p.BatchDuration,
Expand Down Expand Up @@ -764,7 +768,7 @@ func main() {
Name: "new",
Usage: "creates a new CA",
Action: handleCaNew,
ArgsUsage: "<issuer-id> <http-server>",
ArgsUsage: "<issuer-oid> <http-server>",
Flags: []cli.Flag{
&cli.DurationFlag{
Name: "batch-duration",
Expand All @@ -781,6 +785,12 @@ func main() {
Aliases: []string{"s"},
Usage: "time to serve assertions",
},
&cli.StringFlag{
Name: "ca-path",
Aliases: []string{"p"},
Usage: "root directory to store CA files",
Value: ".",
},
},
},
{
Expand Down
Loading