package prefixfile import ( "crypto/ecdsa" "crypto/rand" "crypto/sha256" "encoding/asn1" "encoding/hex" "errors" "fmt" "math/big" "net" "sort" "strconv" "strings" ) func (roalist *ROAList) GenerateDigest() ([]byte, []byte, error) { signroa := make([]string, 0) for _, v := range roalist.Data { signroa = append(signroa, fmt.Sprintf("%v,%v,%v,", v.Prefix, v.Length, v.ASN)) } sort.Strings(signroa) sorted := strings.Join(signroa, "") dgst1 := sha256.Sum256([]byte(sorted)) dgst2 := sha256.Sum256([]byte(fmt.Sprintf("%v,%v%v", roalist.Metadata.Generated, sorted, roalist.Metadata.Valid))) return dgst1[:], dgst2[:], nil } type ecdsaSignature struct { R, S *big.Int } func (roalist *ROAList) CheckFile(key *ecdsa.PublicKey) (bool, bool, error) { dgst1, dgst2, err := roalist.GenerateDigest() if err != nil { return false, false, err } signatureB, err := hex.DecodeString(roalist.Metadata.SignatureDate) if err != nil { return false, false, err } var sign1 ecdsaSignature _, err = asn1.Unmarshal(signatureB, &sign1) if err != nil { return false, false, err } signatureB, err = hex.DecodeString(roalist.Metadata.Signature) if err != nil { return false, false, err } var sign2 ecdsaSignature _, err = asn1.Unmarshal(signatureB, &sign2) if err != nil { return false, false, err } verify1 := ecdsa.Verify(key, dgst1, sign1.R, sign1.S) verify2 := ecdsa.Verify(key, dgst2, sign2.R, sign2.S) return verify1, verify2, err } func (roalist *ROAList) Sign(privkey *ecdsa.PrivateKey) (string, string, error) { dgst1, dgst2, err := roalist.GenerateDigest() if err != nil { return "", "", err } sign1, err := privkey.Sign(rand.Reader, dgst1, nil) if err != nil { return "", "", err } sign2, err := privkey.Sign(rand.Reader, dgst2, nil) if err != nil { return "", "", err } return hex.EncodeToString(sign1), hex.EncodeToString(sign2), nil } type ROAJson struct { Prefix string `json:"prefix"` Length uint8 `json:"maxLength"` ASN interface{} `json:"asn"` TA string `json:"ta,omitempty"` } type MetaData struct { Counts int `json:"counts"` Generated int `json:"generated"` Valid int `json:"valid,omitempty"` Signature string `json:"signature,omitempty"` SignatureDate string `json:"signatureDate,omitempty"` Serial int `json:"serial,omitempty"` } type ROAList struct { Metadata MetaData `json:"metadata,omitempty"` Data []ROAJson `json:"roas"` } func (roa *ROAJson) GetASN2() (uint32, error) { switch asnc := roa.ASN.(type) { case string: asnStr := strings.TrimLeft(asnc, "aAsS") asnInt, err := strconv.ParseUint(asnStr, 10, 32) if err != nil { return 0, errors.New(fmt.Sprintf("Could not decode ASN: %v as part of ROA", roa.ASN)) } asn := uint32(asnInt) return asn, nil case float64: return uint32(asnc), nil case int: return uint32(asnc), nil default: return 0, errors.New(fmt.Sprintf("Could not decode ASN: %v as part of ROA", roa.ASN)) } } func (roa *ROAJson) GetASN() uint32 { asn, _ := roa.GetASN2() return asn } func (roa *ROAJson) SetASN(asn uint32) { roa.ASN = fmt.Sprintf("AS%v", asn) } func (roa *ROAJson) GetPrefix2() (*net.IPNet, error) { _, prefix, err := net.ParseCIDR(roa.Prefix) if err != nil { return nil, errors.New(fmt.Sprintf("Could not decode prefix: %v as part of ROA", roa.Prefix)) } return prefix, nil } func (roa *ROAJson) GetPrefix() *net.IPNet { prefix, _ := roa.GetPrefix2() return prefix } func (roa *ROAJson) GetMaxLen() int { return int(roa.Length) } func (roa *ROAJson) String() string { return fmt.Sprintf("%v/%v/%v", roa.Prefix, roa.Length, roa.ASN) } func GetIPBroadcast(ipnet net.IPNet) net.IP { br := make([]byte, len(ipnet.IP)) for i := 0; i < len(ipnet.IP); i++ { br[i] = ipnet.IP[i] | (^ipnet.Mask[i]) } return net.IP(br) }