mirror of
https://github.com/Egida/EndGame0.git
synced 2025-08-13 08:35:35 -04:00
EndGame v3
This commit is contained in:
commit
9e36ba54ee
646 changed files with 271674 additions and 0 deletions
262
sourcecode/gobalance/pkg/stem/descriptor/certificate.go
Normal file
262
sourcecode/gobalance/pkg/stem/descriptor/certificate.go
Normal file
|
@ -0,0 +1,262 @@
|
|||
package descriptor
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gobalance/pkg/btime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Ed25519Certificate struct {
|
||||
Version uint8
|
||||
}
|
||||
|
||||
// Ed25519CertificateV1 version 1 Ed25519 certificate, which sign tor server and hidden service v3
|
||||
// descriptors.
|
||||
type Ed25519CertificateV1 struct {
|
||||
Ed25519Certificate
|
||||
Typ uint8
|
||||
typInt int64
|
||||
Expiration time.Time
|
||||
KeyType uint8
|
||||
Key ed25519.PublicKey
|
||||
Extensions []Ed25519Extension
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
func (c Ed25519CertificateV1) pack() (out []byte) {
|
||||
out = append(out, c.Version)
|
||||
out = append(out, c.Typ)
|
||||
expiration := c.Expiration.Unix() / 3600
|
||||
expirationBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(expirationBytes, uint32(expiration))
|
||||
out = append(out, expirationBytes...)
|
||||
out = append(out, c.KeyType)
|
||||
out = append(out, c.Key...)
|
||||
out = append(out, uint8(len(c.Extensions)))
|
||||
for _, ext := range c.Extensions {
|
||||
out = append(out, ext.Pack()...)
|
||||
}
|
||||
if c.Signature != nil {
|
||||
out = append(out, c.Signature...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ToBase64 Base64 encoded certificate data.
|
||||
func (c Ed25519CertificateV1) ToBase64() (out string) {
|
||||
b64 := strings.Join(splitByLength(base64.StdEncoding.EncodeToString(c.pack()), 64), "\n")
|
||||
out = fmt.Sprintf("-----BEGIN ED25519 CERT-----\n%s\n-----END ED25519 CERT-----", b64)
|
||||
return out
|
||||
}
|
||||
|
||||
func splitByLength(msg string, size int) (out []string) {
|
||||
for i := 0; i < len(msg); i += size {
|
||||
upper := i + size
|
||||
if i+size > len(msg) {
|
||||
upper = len(msg)
|
||||
}
|
||||
out = append(out, msg[i:upper])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const DefaultExpirationHours = 54 // HSv3 certificate expiration of tor
|
||||
|
||||
func NewEd25519CertificateV1(certType uint8, expiration *time.Time, keyType uint8, key ed25519.PublicKey,
|
||||
extensions []Ed25519Extension, signingKey ed25519.PrivateKey, signature []byte) Ed25519CertificateV1 {
|
||||
c := Ed25519CertificateV1{}
|
||||
c.Version = 1
|
||||
if certType == 0 {
|
||||
panic("Certificate type is required")
|
||||
} else if key == nil {
|
||||
panic("Certificate key is required")
|
||||
}
|
||||
if certType == 8 {
|
||||
c.Typ, c.typInt = HsV3DescSigning, 8
|
||||
} else if certType == 9 {
|
||||
c.Typ, c.typInt = HsV3IntroAuth, 9
|
||||
} else if certType == 11 {
|
||||
c.Typ, c.typInt = HsV3NtorEnc, 11
|
||||
} else {
|
||||
panic("unknown cert type")
|
||||
}
|
||||
if expiration == nil {
|
||||
c.Expiration = btime.Clock.Now().UTC().Add(DefaultExpirationHours * time.Hour)
|
||||
} else {
|
||||
c.Expiration = expiration.UTC()
|
||||
}
|
||||
c.KeyType = keyType
|
||||
c.Key = key
|
||||
c.Extensions = extensions
|
||||
c.Signature = signature
|
||||
if signingKey != nil {
|
||||
calculatedSig := ed25519.Sign(signingKey, c.pack())
|
||||
/*
|
||||
// if caller provides both signing key *and* signature then ensure they match
|
||||
if self.signature and self.signature != calculated_sig:
|
||||
raise ValueError("Signature calculated from its key (%s) mismatches '%s'" % (calculated_sig, self.signature))
|
||||
*/
|
||||
c.Signature = calculatedSig
|
||||
}
|
||||
if c.Typ == LINK || c.Typ == IDENTITY || c.Typ == AUTHENTICATE {
|
||||
logrus.Panicf("Ed25519 certificate cannot have a type of %d. This is reserved for CERTS cells.", c.typInt)
|
||||
} else if c.Typ == ED25519_IDENTITY {
|
||||
panic("Ed25519 certificate cannot have a type of 7. This is reserved for RSA identity cross-certification.")
|
||||
} else if c.Typ == 0 {
|
||||
logrus.Panicf("Ed25519 certificate type %d is unrecognized", c.typInt)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ed25519CertificateV1) SigningKey() ed25519.PublicKey {
|
||||
for _, ext := range c.Extensions {
|
||||
if ext.Typ == HasSigningKey {
|
||||
return ext.Data
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
LINK = iota + 1
|
||||
IDENTITY
|
||||
AUTHENTICATE
|
||||
ED25519_SIGNING
|
||||
LINK_CERT
|
||||
ED25519_AUTHENTICATE
|
||||
ED25519_IDENTITY
|
||||
HsV3DescSigning
|
||||
HsV3IntroAuth
|
||||
NTOR_ONION_KEY
|
||||
HsV3NtorEnc
|
||||
)
|
||||
|
||||
// Ed25519CertificateV1Unpack parses a byte encoded ED25519 certificate.
|
||||
func Ed25519CertificateV1Unpack(content []byte) Ed25519CertificateV1 {
|
||||
if len(content) == 0 {
|
||||
logrus.Panicf("Failed to unpack ed25519 certificate")
|
||||
}
|
||||
version := content[0]
|
||||
if version != 1 {
|
||||
logrus.Panicf("Ed25519 certificate is version %c. Parser presently only supports version 1.", version)
|
||||
}
|
||||
return ed25519CertificateV1Unpack(content)
|
||||
}
|
||||
|
||||
// Ed25519CertificateFromBase64 parses a base64 encoded ED25519 certificate.
|
||||
func Ed25519CertificateFromBase64(content string) Ed25519CertificateV1 {
|
||||
if strings.HasPrefix(content, "-----BEGIN ED25519 CERT-----\n") &&
|
||||
strings.HasSuffix(content, "\n-----END ED25519 CERT-----") {
|
||||
content = strings.TrimPrefix(content, "-----BEGIN ED25519 CERT-----\n")
|
||||
content = strings.TrimSuffix(content, "\n-----END ED25519 CERT-----")
|
||||
}
|
||||
by, err := base64.StdEncoding.DecodeString(content)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if len(by) == 0 {
|
||||
return Ed25519CertificateV1{}
|
||||
}
|
||||
return Ed25519CertificateV1Unpack(by)
|
||||
}
|
||||
|
||||
const (
|
||||
Ed25519KeyLength = 32
|
||||
Ed25519HeaderLength = 40
|
||||
Ed25519SignatureLength = 64
|
||||
)
|
||||
|
||||
func ed25519CertificateV1Unpack(content []byte) Ed25519CertificateV1 {
|
||||
if len(content) < Ed25519HeaderLength+Ed25519SignatureLength {
|
||||
logrus.Panicf("Ed25519 certificate was %d bytes, but should be at least %d", len(content), Ed25519HeaderLength+Ed25519SignatureLength)
|
||||
}
|
||||
header, signature := content[:len(content)-Ed25519SignatureLength], content[len(content)-Ed25519SignatureLength:]
|
||||
|
||||
version, header := header[0], header[1:]
|
||||
certType, header := header[0], header[1:]
|
||||
expirationHoursRaw, header := header[:4], header[4:]
|
||||
var expirationHours int64
|
||||
expirationHours |= int64(expirationHoursRaw[0]) << 24
|
||||
expirationHours |= int64(expirationHoursRaw[1]) << 16
|
||||
expirationHours |= int64(expirationHoursRaw[2]) << 8
|
||||
expirationHours |= int64(expirationHoursRaw[3])
|
||||
keyType, header := header[0], header[1:]
|
||||
key, header := header[:Ed25519KeyLength], header[Ed25519KeyLength:]
|
||||
extensionCount, extensionData := header[0], header[1:]
|
||||
if version != 1 {
|
||||
logrus.Panicf("Ed25519 v1 parser cannot read version %c certificates", version)
|
||||
}
|
||||
extensions := make([]Ed25519Extension, 0)
|
||||
for i := 0; i < int(extensionCount); i++ {
|
||||
var extension Ed25519Extension
|
||||
extension, extensionData = Ed25519ExtensionPop(extensionData)
|
||||
extensions = append(extensions, extension)
|
||||
}
|
||||
if len(extensionData) > 0 {
|
||||
logrus.Panicf("Ed25519 certificate had %d bytes of unused extension data", len(extensionData))
|
||||
}
|
||||
expiration := time.Unix(int64(expirationHours)*3600, 0)
|
||||
return NewEd25519CertificateV1(certType,
|
||||
&expiration,
|
||||
keyType, key, extensions, nil, signature)
|
||||
}
|
||||
|
||||
type Ed25519Extension struct {
|
||||
Typ uint8
|
||||
Flags []string
|
||||
FlagInt uint8
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func NewEd25519Extension(extType, flagVal uint8, data []byte) Ed25519Extension {
|
||||
e := Ed25519Extension{}
|
||||
e.Typ = extType
|
||||
e.Flags = make([]string, 0)
|
||||
e.FlagInt = flagVal
|
||||
e.Data = data
|
||||
if flagVal > 0 && flagVal%2 == 1 {
|
||||
e.Flags = append(e.Flags, "AFFECTS_VALIDATION")
|
||||
flagVal -= 1
|
||||
}
|
||||
if flagVal > 0 {
|
||||
e.Flags = append(e.Flags, "UNKNOWN")
|
||||
}
|
||||
if extType == HasSigningKey && len(data) != 32 {
|
||||
logrus.Panicf("Ed25519 HAS_SIGNING_KEY extension must be 32 bytes, but was %d.", len(data))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func Ed25519ExtensionPop(content []byte) (Ed25519Extension, []byte) {
|
||||
if len(content) < 4 {
|
||||
panic("Ed25519 extension is missing header fields")
|
||||
}
|
||||
|
||||
dataSizeRaw, content := content[:2], content[2:]
|
||||
var dataSize int64
|
||||
dataSize |= int64(dataSizeRaw[0]) << 8
|
||||
dataSize |= int64(dataSizeRaw[1])
|
||||
extType, content := content[0], content[1:]
|
||||
flags, content := content[0], content[1:]
|
||||
data, content := content[:dataSize], content[dataSize:]
|
||||
|
||||
if int64(len(data)) != dataSize {
|
||||
logrus.Panicf("Ed25519 extension is truncated. It should have %d bytes of data but there's only %d.", dataSize, len(data))
|
||||
}
|
||||
|
||||
return NewEd25519Extension(extType, flags, data), content
|
||||
}
|
||||
|
||||
func (e Ed25519Extension) Pack() (out []byte) {
|
||||
dataSizeBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(dataSizeBytes, uint16(len(e.Data)))
|
||||
out = append(out, dataSizeBytes...)
|
||||
out = append(out, e.Typ)
|
||||
out = append(out, e.FlagInt)
|
||||
out = append(out, e.Data...)
|
||||
return
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue