forked from cloudflare/cfrpki
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
317 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package ca | ||
|
||
import ( | ||
"bytes" | ||
"encoding/xml" | ||
"io" | ||
) | ||
|
||
const ( | ||
XML_VERSION_RFC8181 = 4 | ||
XML_VERSION_RFC8183 = 1 | ||
) | ||
|
||
type XMLMessage struct { | ||
XMLName xml.Name `xml:"http://www.hactrn.net/uris/rpki/publication-spec/ msg"` | ||
Version int `xml:"version,attr"` | ||
Type string `xml:"type,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
type XMLMessageChildRequest struct { | ||
XMLName xml.Name `xml:"http://www.hactrn.net/uris/rpki/rpki-setup/ child_request"` | ||
Version int `xml:"version,attr"` | ||
ChildHandle string `xml:"child_handle,attr"` | ||
Tag string `xml:"tag,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
type XMLMessageParentResponse struct { | ||
XMLName xml.Name `xml:"http://www.hactrn.net/uris/rpki/rpki-setup/ parent_response"` | ||
Version int `xml:"version,attr"` | ||
Tag string `xml:"tag,attr"` | ||
ServiceURI string `xml:"service_uri,attr"` | ||
ChildHandle string `xml:"child_handle,attr"` | ||
ParentHandle string `xml:"parent_handle,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
type XMLMessagePublisherRequest struct { | ||
XMLName xml.Name `xml:"http://www.hactrn.net/uris/rpki/rpki-setup/ publisher_request"` | ||
Version int `xml:"version,attr"` | ||
Tag string `xml:"tag,attr"` | ||
PublisherHandle string `xml:"publisher_handle,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
type XMLMessageRepositoryResponse struct { | ||
XMLName xml.Name `xml:"http://www.hactrn.net/uris/rpki/rpki-setup/ repository_response"` | ||
Version int `xml:"version,attr"` | ||
Tag string `xml:"tag,attr"` | ||
ServiceURI string `xml:"service_uri,attr"` | ||
SIABase string `xml:"sia_base,attr"` | ||
RRDPNotificationURI string `xml:"rrdp_notification_uri,attr"` | ||
PublisherHandle string `xml:"publisher_handle,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
func NewXMLList() *XMLMessage { | ||
return &XMLMessage{ | ||
Version: XML_VERSION_RFC8181, | ||
Type: "query", | ||
Inner: "<list/>", | ||
} | ||
} | ||
|
||
type Content struct { | ||
XMLName xml.Name | ||
Hash string `xml:"hash,attr"` | ||
ErrorCode string `xml:"error_code,attr"` | ||
Tag string `xml:"tag,attr"` | ||
URI string `xml:"uri,attr"` | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
func DecodeInner(inner []byte) ([]Content, error) { | ||
var innerContent []Content | ||
var err error | ||
if len(inner) > 0 { | ||
buf := bytes.NewBuffer(inner) | ||
dec := xml.NewDecoder(buf) | ||
for err == nil { | ||
err = dec.Decode(&innerContent) | ||
} | ||
if err == io.EOF { | ||
err = nil | ||
} | ||
} | ||
return innerContent, err | ||
} | ||
|
||
func DecodeXML(message []byte) (*XMLMessage, error) { | ||
var msg XMLMessage | ||
buf := bytes.NewBuffer(message) | ||
dec := xml.NewDecoder(buf) | ||
err := dec.Decode(&msg) | ||
return &msg, err | ||
} | ||
|
||
func DecodeXMLFull(message []byte) (*XMLMessage, []Content, error) { | ||
var msg XMLMessage | ||
buf := bytes.NewBuffer(message) | ||
dec := xml.NewDecoder(buf) | ||
err := dec.Decode(&msg) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
innerContent, err := DecodeInner([]byte(msg.Inner)) | ||
return &msg, innerContent, err | ||
} | ||
|
||
func DecodeXMLCRFull(message []byte) (*XMLMessageChildRequest, []Content, error) { | ||
var msg XMLMessageChildRequest | ||
buf := bytes.NewBuffer(message) | ||
dec := xml.NewDecoder(buf) | ||
err := dec.Decode(&msg) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
innerContent, err := DecodeInner([]byte(msg.Inner)) | ||
return &msg, innerContent, err | ||
} | ||
|
||
func DecodeXMLPRFull(message []byte) (*XMLMessageParentResponse, []Content, error) { | ||
var msg XMLMessageParentResponse | ||
buf := bytes.NewBuffer(message) | ||
dec := xml.NewDecoder(buf) | ||
err := dec.Decode(&msg) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
innerContent, err := DecodeInner([]byte(msg.Inner)) | ||
return &msg, innerContent, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package librpki | ||
|
||
import ( | ||
"bytes" | ||
"encoding/asn1" | ||
"encoding/xml" | ||
) | ||
|
||
var ( | ||
XMLOID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 28} | ||
) | ||
|
||
type XML struct { | ||
OID asn1.ObjectIdentifier | ||
EContent asn1.RawValue `asn1:"tag:0,explicit,optional"` | ||
} | ||
|
||
type XMLContent struct { | ||
Message interface{} | ||
} | ||
|
||
type RPKI_XML struct { | ||
Content []byte | ||
Certificate *RPKI_Certificate | ||
|
||
InnerValid bool | ||
InnerValidityError error | ||
} | ||
|
||
func EncodeXMLContent(content interface{}) (*XML, error) { | ||
buf := bytes.NewBuffer([]byte{}) | ||
enc := xml.NewEncoder(buf) | ||
err := enc.Encode(content) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return EncodeXMLData(buf.Bytes()) | ||
} | ||
|
||
func EncodeXMLData(message []byte) (*XML, error) { | ||
eContentEnc, err := asn1.MarshalWithParams(message, "tag:0,explicit") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
xmlContent := &XML{ | ||
OID: XMLOID, | ||
EContent: asn1.RawValue{FullBytes: eContentEnc}, | ||
} | ||
return xmlContent, nil | ||
} | ||
|
||
func DecodeXML(data []byte) (*RPKI_XML, error) { | ||
c, err := DecodeCMS(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var rawxml XML | ||
_, err = asn1.Unmarshal(c.SignedData.EncapContentInfo.FullBytes, &rawxml) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var inner asn1.RawValue | ||
_, err = asn1.Unmarshal(rawxml.EContent.Bytes, &inner) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var rpki_xml RPKI_XML | ||
rpki_xml.Content = inner.Bytes | ||
|
||
cert, err := c.GetRPKICertificate() | ||
if err != nil { | ||
return &rpki_xml, err | ||
} | ||
rpki_xml.Certificate = cert | ||
|
||
err = c.Validate(inner.Bytes, cert.Certificate) | ||
if err != nil { | ||
rpki_xml.InnerValidityError = err | ||
} else { | ||
rpki_xml.InnerValid = true | ||
} | ||
|
||
return &rpki_xml, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package librpki | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
"encoding/hex" | ||
"github.com/stretchr/testify/assert" | ||
"math/big" | ||
"strings" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestEncodeXMLContent(t *testing.T) { | ||
msg := []byte(`<msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" version="4" type="query"><list /></msg>`) | ||
contentEnc, err := EncodeXMLData(msg) | ||
assert.Nil(t, err) | ||
|
||
now := time.Now().UTC() | ||
cms, err := EncodeCMS(nil, contentEnc, now) | ||
assert.Nil(t, err) | ||
|
||
privkeyParent, err := rsa.GenerateKey(rand.Reader, 2048) | ||
skiParent, _ := HashRSAPublicKey(*privkeyParent.Public().(*rsa.PublicKey)) | ||
|
||
parentCert := &x509.Certificate{ | ||
Version: 1, | ||
SerialNumber: big.NewInt(1), | ||
Subject: pkix.Name{ | ||
CommonName: strings.ToUpper(hex.EncodeToString(skiParent)), | ||
}, | ||
NotBefore: now.Add(-time.Minute * 5), | ||
NotAfter: now.Add(time.Hour * 24 * (365*100 + 24)), | ||
SubjectKeyId: skiParent, | ||
} | ||
|
||
privkey, err := rsa.GenerateKey(rand.Reader, 2048) | ||
ski, _ := HashRSAPublicKey(*privkey.Public().(*rsa.PublicKey)) | ||
|
||
cert := &x509.Certificate{ | ||
Version: 1, | ||
SerialNumber: big.NewInt(1), | ||
Subject: pkix.Name{ | ||
CommonName: strings.ToUpper(hex.EncodeToString(ski)), | ||
}, | ||
NotBefore: now.Add(-time.Minute * 5), | ||
NotAfter: now.Add(time.Hour * 24 * (365*100 + 24)), | ||
SubjectKeyId: ski, | ||
} | ||
pubkey := privkey.Public() | ||
certBytes, err := x509.CreateCertificate(rand.Reader, cert, parentCert, pubkey, privkeyParent) | ||
|
||
crls, err := parentCert.CreateCRL(rand.Reader, privkeyParent, []pkix.RevokedCertificate{}, now.Add(-time.Minute*5), now.Add(time.Minute*5)) | ||
assert.Nil(t, err) | ||
cms.AddCRLs(crls) | ||
|
||
encap, _ := EContentToEncapBF(contentEnc.EContent.FullBytes, true) | ||
err = cms.Sign(rand.Reader, ski, encap, privkey, certBytes) | ||
assert.Nil(t, err) | ||
|
||
entriesBytes, err := asn1.Marshal(*cms) | ||
assert.Nil(t, err) | ||
|
||
data, err := DecodeXML(entriesBytes) | ||
assert.Nil(t, err) | ||
assert.Equal(t, data.Content, msg) | ||
assert.Equal(t, data.InnerValid, true) | ||
} |