Merge #134: Support AIA and compressed pubkeys

7287e92825 Fix nlreturn warning (Jeremy Rand)
c0694b002d Fix name field of cached TLSA records (Jeremy Rand)
5336820800 Add "aia" MetaDomain (Jeremy Rand)
88affcd3fe TLS: Add compressed pubkey support (Jeremy Rand)

Pull request description:

  Refs namecoin/safetlsa#3

Top commit has no ACKs.

Tree-SHA512: 77984e8674814b8ac586d98f83725b9901a942218e7c4d34cfe6d390f6e0994c943978132a36d4f1812245ce8700275570235ccdec434f186607d8de72bffab5
pull/135/head
Jeremy Rand 3 years ago
commit e4be195b7a
No known key found for this signature in database
GPG Key ID: FD7550C2EB800711

@ -13,6 +13,8 @@ task:
- source testdata/move_to_gopath.bash - source testdata/move_to_gopath.bash
fetch_script: fetch_script:
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/... - go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
- go generate github.com/namecoin/x509-compressed/...
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
lint_script: lint_script:
- cd $(go env GOPATH)/src/github.com/$CIRRUS_REPO_FULL_NAME/ - cd $(go env GOPATH)/src/github.com/$CIRRUS_REPO_FULL_NAME/
- golangci-lint run --no-config --enable-all --disable gochecknoglobals,gomnd $GOLANGCI_ARGS -v --timeout 5m --out-format json > $CIRRUS_WORKING_DIR/lint-report.json - golangci-lint run --no-config --enable-all --disable gochecknoglobals,gomnd $GOLANGCI_ARGS -v --timeout 5m --out-format json > $CIRRUS_WORKING_DIR/lint-report.json
@ -59,6 +61,8 @@ task:
- source testdata/move_to_gopath.bash - source testdata/move_to_gopath.bash
fetch_script: fetch_script:
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/... - go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
- go generate github.com/namecoin/x509-compressed/...
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
test_script: go test -tags "$GOX_TAGS" -v github.com/$CIRRUS_REPO_FULL_NAME/... test_script: go test -tags "$GOX_TAGS" -v github.com/$CIRRUS_REPO_FULL_NAME/...
env: env:
GOX_TAGS: "" GOX_TAGS: ""
@ -85,6 +89,8 @@ task:
fetch_script: fetch_script:
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/... - go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
- GOOS=windows GOARCH=amd64 go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/... - GOOS=windows GOARCH=amd64 go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
- go generate github.com/namecoin/x509-compressed/...
- go get -tags "$GOX_TAGS" -d -v -t github.com/$CIRRUS_REPO_FULL_NAME/...
build_script: build_script:
- rm -rf idist - rm -rf idist
- CGO_ENABLED=1 gox -tags="$GOX_TAGS" -parallel=8 -osarch 'linux/386 linux/amd64 linux/arm linux/arm64 linux/ppc64le' -output "$GOPATH/releasing/idist/$CIRRUS_REPO_NAME-$CIRRUS_TAG-{{.OS}}_{{.Arch}}/bin/{{.Dir}}" github.com/$CIRRUS_REPO_FULL_NAME/... - CGO_ENABLED=1 gox -tags="$GOX_TAGS" -parallel=8 -osarch 'linux/386 linux/amd64 linux/arm linux/arm64 linux/ppc64le' -output "$GOPATH/releasing/idist/$CIRRUS_REPO_NAME-$CIRRUS_TAG-{{.OS}}_{{.Arch}}/bin/{{.Dir}}" github.com/$CIRRUS_REPO_FULL_NAME/...

@ -96,9 +96,13 @@ Option A: Using Go build commands (works on any platform):
familar with Go, setting it to the path to an empty directory will suffice. familar with Go, setting it to the path to an empty directory will suffice.
The directory will be filled with build files.) The directory will be filled with build files.)
2. Run `go get -t -u github.com/namecoin/ncdns/...`. The ncdns source code will be 2. Run `go get -d -t -u github.com/namecoin/ncdns/...`. The ncdns source code will be
retrieved automatically, and ncdns will be built. The binaries will be at retrieved automatically.
$GOPATH/bin/ncdns..
3. Run `go generate github.com/namecoin/x509_compressed/...`. The compressed public key patch will be applied.
4. Run `go get -t -u github.com/namecoin/ncdns/...`. ncdns will be built. The binaries will be at
$GOPATH/bin/ncdns.
Option B: Using Makefile (non-Windows platforms): Option B: Using Makefile (non-Windows platforms):

@ -252,6 +252,19 @@ func (tx *btx) doMetaDomain() (rrs []dns.RR, err error) {
A: ip, A: ip,
}, },
} }
case "aia":
// TODO: Make AIA address configurable (currently hardcoded to "this.x--nmc.bit")
rrs = []dns.RR{
&dns.CNAME{
Hdr: dns.RR_Header{
Name: dns.Fqdn("aia." + tx.basename + "." + tx.rootname),
Ttl: 86400,
Class: dns.ClassINET,
Rrtype: dns.TypeCNAME,
},
Target: dns.Fqdn("this." + tx.basename + "." + tx.rootname),
},
}
default: default:
} }
@ -283,22 +296,7 @@ type domain struct {
ncv *ncdomain.Value ncv *ncdomain.Value
} }
func (b *Backend) getNamecoinEntry(name, streamIsolationID string) (*domain, error) { func (b *Backend) resolveNameCache(name, streamIsolationID string) *string {
d := b.getNamecoinEntryCache(name, streamIsolationID)
if d != nil {
return d, nil
}
d, err := b.getNamecoinEntryLL(name, streamIsolationID)
if err != nil {
return nil, err
}
b.addNamecoinEntryToCache(name, d, streamIsolationID)
return d, nil
}
func (b *Backend) getNamecoinEntryCache(name, streamIsolationID string) *domain {
b.cacheMutex.Lock() b.cacheMutex.Lock()
defer b.cacheMutex.Unlock() defer b.cacheMutex.Unlock()
@ -308,14 +306,15 @@ func (b *Backend) getNamecoinEntryCache(name, streamIsolationID string) *domain
} }
if dd, ok := cache.Get(name); ok { if dd, ok := cache.Get(name); ok {
d := dd.(*domain) v := dd.(*string)
return d
return v
} }
return nil return nil
} }
func (b *Backend) addNamecoinEntryToCache(name string, d *domain, streamIsolationID string) { func (b *Backend) addNamecoinJSONToCache(name string, jsonValue *string, streamIsolationID string) {
b.cacheMutex.Lock() b.cacheMutex.Lock()
defer b.cacheMutex.Unlock() defer b.cacheMutex.Unlock()
@ -327,16 +326,25 @@ func (b *Backend) addNamecoinEntryToCache(name string, d *domain, streamIsolatio
cache = b.caches[streamIsolationID] cache = b.caches[streamIsolationID]
} }
cache.Add(name, d) cache.Add(name, jsonValue)
} }
func (b *Backend) getNamecoinEntryLL(name, streamIsolationID string) (*domain, error) { func (b *Backend) getNamecoinEntry(name, streamIsolationID string) (*domain, error) {
v, err := b.resolveName(name, streamIsolationID) // Try the cache first
if err != nil { v := b.resolveNameCache(name, streamIsolationID)
return nil, err
// If the cache misses, resolve it via namecoind
if v == nil {
vv, err := b.resolveName(name, streamIsolationID)
if err != nil {
return nil, err
}
v = &vv
b.addNamecoinJSONToCache(name, v, streamIsolationID)
} }
d, err := b.jsonToDomain(name, v, streamIsolationID) d, err := b.jsonToDomain(name, *v, streamIsolationID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -13,6 +13,7 @@ import (
"github.com/namecoin/ncdns/certdehydrate" "github.com/namecoin/ncdns/certdehydrate"
"github.com/namecoin/ncdns/util" "github.com/namecoin/ncdns/util"
x509_compressed "github.com/namecoin/x509-compressed/x509"
) )
type Value struct { type Value struct {
@ -77,34 +78,34 @@ func parseTLSADehydrated(tlsa1dehydrated interface{}, v *Value) error {
func parseTLSADANE(tlsa1dane interface{}, v *Value) error { func parseTLSADANE(tlsa1dane interface{}, v *Value) error {
if tlsa, ok := tlsa1dane.([]interface{}); ok { if tlsa, ok := tlsa1dane.([]interface{}); ok {
// Format: ["443", "tcp", 1, 2, 3, "base64 certificate data"] // Format: [1, 2, 3, "base64 certificate data"]
if len(tlsa) < 4 { if len(tlsa) < 4 {
return fmt.Errorf("TLSA item must have six items") return fmt.Errorf("TLSA item must have four items")
} }
a1, ok := tlsa[0].(float64) a1, ok := tlsa[0].(float64)
if !ok { if !ok {
return fmt.Errorf("Third item in TLSA value must be an integer (usage)") return fmt.Errorf("First item in TLSA value must be an integer (usage)")
} }
a2, ok := tlsa[1].(float64) a2, ok := tlsa[1].(float64)
if !ok { if !ok {
return fmt.Errorf("Fourth item in TLSA value must be an integer (selector)") return fmt.Errorf("Second item in TLSA value must be an integer (selector)")
} }
a3, ok := tlsa[2].(float64) a3, ok := tlsa[2].(float64)
if !ok { if !ok {
return fmt.Errorf("Fifth item in TLSA value must be an integer (match type)") return fmt.Errorf("Third item in TLSA value must be an integer (match type)")
} }
a4, ok := tlsa[3].(string) a4, ok := tlsa[3].(string)
if !ok { if !ok {
return fmt.Errorf("Sixth item in TLSA value must be a string (certificate)") return fmt.Errorf("Fourth item in TLSA value must be a string (certificate)")
} }
a4b, err := base64.StdEncoding.DecodeString(a4) a4b, err := base64.StdEncoding.DecodeString(a4)
if err != nil { if err != nil {
return fmt.Errorf("Fourth item in DS value must be valid base64: %v", err) return fmt.Errorf("Fourth item in TLSA value must be valid base64: %v", err)
} }
a4h := hex.EncodeToString(a4b) a4h := hex.EncodeToString(a4b)
@ -118,6 +119,36 @@ func parseTLSADANE(tlsa1dane interface{}, v *Value) error {
Certificate: strings.ToUpper(a4h), Certificate: strings.ToUpper(a4h),
}) })
// Handle compressed public keys specially
// Check if this TLSA is a public key preimage
if uint8(a2) == 1 && uint8(a3) == 0 {
pubDecompressed, err := x509_compressed.ParsePKIXPublicKey(a4b)
if err != nil {
return nil
}
pubDecompressedBytes, err := x509.MarshalPKIXPublicKey(pubDecompressed)
if err != nil {
return nil
}
pubDecompressedHex := hex.EncodeToString(pubDecompressedBytes)
if pubDecompressedHex == a4h {
// The pubkey wasn't compressed, so decompressing had no impact.
return nil
}
v.TLSA = append(v.TLSA, &dns.TLSA{
Hdr: dns.RR_Header{Name: "", Rrtype: dns.TypeTLSA, Class: dns.ClassINET,
Ttl: defaultTTL},
Usage: uint8(a1),
Selector: uint8(a2),
MatchingType: uint8(a3),
Certificate: strings.ToUpper(pubDecompressedHex),
})
}
return nil return nil
} else { } else {
return fmt.Errorf("TLSA item must be an array") return fmt.Errorf("TLSA item must be an array")

Loading…
Cancel
Save