mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-22 10:12:11 +00:00
654 lines
16 KiB
Go
654 lines
16 KiB
Go
|
package sprig
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto"
|
||
|
"crypto/aes"
|
||
|
"crypto/cipher"
|
||
|
"crypto/dsa"
|
||
|
"crypto/ecdsa"
|
||
|
"crypto/ed25519"
|
||
|
"crypto/elliptic"
|
||
|
"crypto/hmac"
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/sha1"
|
||
|
"crypto/sha256"
|
||
|
"crypto/x509"
|
||
|
"crypto/x509/pkix"
|
||
|
"encoding/asn1"
|
||
|
"encoding/base64"
|
||
|
"encoding/binary"
|
||
|
"encoding/hex"
|
||
|
"encoding/pem"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"hash/adler32"
|
||
|
"io"
|
||
|
"math/big"
|
||
|
"net"
|
||
|
"time"
|
||
|
|
||
|
"strings"
|
||
|
|
||
|
"github.com/google/uuid"
|
||
|
bcrypt_lib "golang.org/x/crypto/bcrypt"
|
||
|
"golang.org/x/crypto/scrypt"
|
||
|
)
|
||
|
|
||
|
func sha256sum(input string) string {
|
||
|
hash := sha256.Sum256([]byte(input))
|
||
|
return hex.EncodeToString(hash[:])
|
||
|
}
|
||
|
|
||
|
func sha1sum(input string) string {
|
||
|
hash := sha1.Sum([]byte(input))
|
||
|
return hex.EncodeToString(hash[:])
|
||
|
}
|
||
|
|
||
|
func adler32sum(input string) string {
|
||
|
hash := adler32.Checksum([]byte(input))
|
||
|
return fmt.Sprintf("%d", hash)
|
||
|
}
|
||
|
|
||
|
func bcrypt(input string) string {
|
||
|
hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost)
|
||
|
if err != nil {
|
||
|
return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)
|
||
|
}
|
||
|
|
||
|
return string(hash)
|
||
|
}
|
||
|
|
||
|
func htpasswd(username string, password string) string {
|
||
|
if strings.Contains(username, ":") {
|
||
|
return fmt.Sprintf("invalid username: %s", username)
|
||
|
}
|
||
|
return fmt.Sprintf("%s:%s", username, bcrypt(password))
|
||
|
}
|
||
|
|
||
|
func randBytes(count int) (string, error) {
|
||
|
buf := make([]byte, count)
|
||
|
if _, err := rand.Read(buf); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return base64.StdEncoding.EncodeToString(buf), nil
|
||
|
}
|
||
|
|
||
|
// uuidv4 provides a safe and secure UUID v4 implementation
|
||
|
func uuidv4() string {
|
||
|
return uuid.New().String()
|
||
|
}
|
||
|
|
||
|
var masterPasswordSeed = "com.lyndir.masterpassword"
|
||
|
|
||
|
var passwordTypeTemplates = map[string][][]byte{
|
||
|
"maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")},
|
||
|
"long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"),
|
||
|
[]byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"),
|
||
|
[]byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"),
|
||
|
[]byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"),
|
||
|
[]byte("CvccCvcvCvccno")},
|
||
|
"medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")},
|
||
|
"short": {[]byte("Cvcn")},
|
||
|
"basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")},
|
||
|
"pin": {[]byte("nnnn")},
|
||
|
}
|
||
|
|
||
|
var templateCharacters = map[byte]string{
|
||
|
'V': "AEIOU",
|
||
|
'C': "BCDFGHJKLMNPQRSTVWXYZ",
|
||
|
'v': "aeiou",
|
||
|
'c': "bcdfghjklmnpqrstvwxyz",
|
||
|
'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",
|
||
|
'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",
|
||
|
'n': "0123456789",
|
||
|
'o': "@&%?,=[]_:-+*$#!'^~;()/.",
|
||
|
'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",
|
||
|
}
|
||
|
|
||
|
func derivePassword(counter uint32, passwordType, password, user, site string) string {
|
||
|
var templates = passwordTypeTemplates[passwordType]
|
||
|
if templates == nil {
|
||
|
return fmt.Sprintf("cannot find password template %s", passwordType)
|
||
|
}
|
||
|
|
||
|
var buffer bytes.Buffer
|
||
|
buffer.WriteString(masterPasswordSeed)
|
||
|
binary.Write(&buffer, binary.BigEndian, uint32(len(user)))
|
||
|
buffer.WriteString(user)
|
||
|
|
||
|
salt := buffer.Bytes()
|
||
|
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64)
|
||
|
if err != nil {
|
||
|
return fmt.Sprintf("failed to derive password: %s", err)
|
||
|
}
|
||
|
|
||
|
buffer.Truncate(len(masterPasswordSeed))
|
||
|
binary.Write(&buffer, binary.BigEndian, uint32(len(site)))
|
||
|
buffer.WriteString(site)
|
||
|
binary.Write(&buffer, binary.BigEndian, counter)
|
||
|
|
||
|
var hmacv = hmac.New(sha256.New, key)
|
||
|
hmacv.Write(buffer.Bytes())
|
||
|
var seed = hmacv.Sum(nil)
|
||
|
var temp = templates[int(seed[0])%len(templates)]
|
||
|
|
||
|
buffer.Truncate(0)
|
||
|
for i, element := range temp {
|
||
|
passChars := templateCharacters[element]
|
||
|
passChar := passChars[int(seed[i+1])%len(passChars)]
|
||
|
buffer.WriteByte(passChar)
|
||
|
}
|
||
|
|
||
|
return buffer.String()
|
||
|
}
|
||
|
|
||
|
func generatePrivateKey(typ string) string {
|
||
|
var priv interface{}
|
||
|
var err error
|
||
|
switch typ {
|
||
|
case "", "rsa":
|
||
|
// good enough for government work
|
||
|
priv, err = rsa.GenerateKey(rand.Reader, 4096)
|
||
|
case "dsa":
|
||
|
key := new(dsa.PrivateKey)
|
||
|
// again, good enough for government work
|
||
|
if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil {
|
||
|
return fmt.Sprintf("failed to generate dsa params: %s", err)
|
||
|
}
|
||
|
err = dsa.GenerateKey(key, rand.Reader)
|
||
|
priv = key
|
||
|
case "ecdsa":
|
||
|
// again, good enough for government work
|
||
|
priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||
|
case "ed25519":
|
||
|
_, priv, err = ed25519.GenerateKey(rand.Reader)
|
||
|
default:
|
||
|
return "Unknown type " + typ
|
||
|
}
|
||
|
if err != nil {
|
||
|
return fmt.Sprintf("failed to generate private key: %s", err)
|
||
|
}
|
||
|
|
||
|
return string(pem.EncodeToMemory(pemBlockForKey(priv)))
|
||
|
}
|
||
|
|
||
|
// DSAKeyFormat stores the format for DSA keys.
|
||
|
// Used by pemBlockForKey
|
||
|
type DSAKeyFormat struct {
|
||
|
Version int
|
||
|
P, Q, G, Y, X *big.Int
|
||
|
}
|
||
|
|
||
|
func pemBlockForKey(priv interface{}) *pem.Block {
|
||
|
switch k := priv.(type) {
|
||
|
case *rsa.PrivateKey:
|
||
|
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||
|
case *dsa.PrivateKey:
|
||
|
val := DSAKeyFormat{
|
||
|
P: k.P, Q: k.Q, G: k.G,
|
||
|
Y: k.Y, X: k.X,
|
||
|
}
|
||
|
bytes, _ := asn1.Marshal(val)
|
||
|
return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes}
|
||
|
case *ecdsa.PrivateKey:
|
||
|
b, _ := x509.MarshalECPrivateKey(k)
|
||
|
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
|
||
|
default:
|
||
|
// attempt PKCS#8 format for all other keys
|
||
|
b, err := x509.MarshalPKCS8PrivateKey(k)
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
return &pem.Block{Type: "PRIVATE KEY", Bytes: b}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) {
|
||
|
block, _ := pem.Decode([]byte(pemBlock))
|
||
|
if block == nil {
|
||
|
return nil, errors.New("no PEM data in input")
|
||
|
}
|
||
|
|
||
|
if block.Type == "PRIVATE KEY" {
|
||
|
priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err)
|
||
|
}
|
||
|
return priv, nil
|
||
|
} else if !strings.HasSuffix(block.Type, " PRIVATE KEY") {
|
||
|
return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type)
|
||
|
}
|
||
|
|
||
|
switch block.Type[:len(block.Type)-12] { // strip " PRIVATE KEY"
|
||
|
case "RSA":
|
||
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err)
|
||
|
}
|
||
|
return priv, nil
|
||
|
case "EC":
|
||
|
priv, err := x509.ParseECPrivateKey(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("parsing EC private key from PEM: %s", err)
|
||
|
}
|
||
|
return priv, nil
|
||
|
case "DSA":
|
||
|
var k DSAKeyFormat
|
||
|
_, err := asn1.Unmarshal(block.Bytes, &k)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err)
|
||
|
}
|
||
|
priv := &dsa.PrivateKey{
|
||
|
PublicKey: dsa.PublicKey{
|
||
|
Parameters: dsa.Parameters{
|
||
|
P: k.P, Q: k.Q, G: k.G,
|
||
|
},
|
||
|
Y: k.Y,
|
||
|
},
|
||
|
X: k.X,
|
||
|
}
|
||
|
return priv, nil
|
||
|
default:
|
||
|
return nil, fmt.Errorf("invalid private key type %s", block.Type)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) {
|
||
|
switch k := priv.(type) {
|
||
|
case interface{ Public() crypto.PublicKey }:
|
||
|
return k.Public(), nil
|
||
|
case *dsa.PrivateKey:
|
||
|
return &k.PublicKey, nil
|
||
|
default:
|
||
|
return nil, fmt.Errorf("unable to get public key for type %T", priv)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type certificate struct {
|
||
|
Cert string
|
||
|
Key string
|
||
|
}
|
||
|
|
||
|
func buildCustomCertificate(b64cert string, b64key string) (certificate, error) {
|
||
|
crt := certificate{}
|
||
|
|
||
|
cert, err := base64.StdEncoding.DecodeString(b64cert)
|
||
|
if err != nil {
|
||
|
return crt, errors.New("unable to decode base64 certificate")
|
||
|
}
|
||
|
|
||
|
key, err := base64.StdEncoding.DecodeString(b64key)
|
||
|
if err != nil {
|
||
|
return crt, errors.New("unable to decode base64 private key")
|
||
|
}
|
||
|
|
||
|
decodedCert, _ := pem.Decode(cert)
|
||
|
if decodedCert == nil {
|
||
|
return crt, errors.New("unable to decode certificate")
|
||
|
}
|
||
|
_, err = x509.ParseCertificate(decodedCert.Bytes)
|
||
|
if err != nil {
|
||
|
return crt, fmt.Errorf(
|
||
|
"error parsing certificate: decodedCert.Bytes: %s",
|
||
|
err,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
_, err = parsePrivateKeyPEM(string(key))
|
||
|
if err != nil {
|
||
|
return crt, fmt.Errorf(
|
||
|
"error parsing private key: %s",
|
||
|
err,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
crt.Cert = string(cert)
|
||
|
crt.Key = string(key)
|
||
|
|
||
|
return crt, nil
|
||
|
}
|
||
|
|
||
|
func generateCertificateAuthority(
|
||
|
cn string,
|
||
|
daysValid int,
|
||
|
) (certificate, error) {
|
||
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
|
||
|
}
|
||
|
|
||
|
return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
|
||
|
}
|
||
|
|
||
|
func generateCertificateAuthorityWithPEMKey(
|
||
|
cn string,
|
||
|
daysValid int,
|
||
|
privPEM string,
|
||
|
) (certificate, error) {
|
||
|
priv, err := parsePrivateKeyPEM(privPEM)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("parsing private key: %s", err)
|
||
|
}
|
||
|
return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
|
||
|
}
|
||
|
|
||
|
func generateCertificateAuthorityWithKeyInternal(
|
||
|
cn string,
|
||
|
daysValid int,
|
||
|
priv crypto.PrivateKey,
|
||
|
) (certificate, error) {
|
||
|
ca := certificate{}
|
||
|
|
||
|
template, err := getBaseCertTemplate(cn, nil, nil, daysValid)
|
||
|
if err != nil {
|
||
|
return ca, err
|
||
|
}
|
||
|
// Override KeyUsage and IsCA
|
||
|
template.KeyUsage = x509.KeyUsageKeyEncipherment |
|
||
|
x509.KeyUsageDigitalSignature |
|
||
|
x509.KeyUsageCertSign
|
||
|
template.IsCA = true
|
||
|
|
||
|
ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)
|
||
|
|
||
|
return ca, err
|
||
|
}
|
||
|
|
||
|
func generateSelfSignedCertificate(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
) (certificate, error) {
|
||
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
|
||
|
}
|
||
|
return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
|
||
|
}
|
||
|
|
||
|
func generateSelfSignedCertificateWithPEMKey(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
privPEM string,
|
||
|
) (certificate, error) {
|
||
|
priv, err := parsePrivateKeyPEM(privPEM)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("parsing private key: %s", err)
|
||
|
}
|
||
|
return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
|
||
|
}
|
||
|
|
||
|
func generateSelfSignedCertificateWithKeyInternal(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
priv crypto.PrivateKey,
|
||
|
) (certificate, error) {
|
||
|
cert := certificate{}
|
||
|
|
||
|
template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
|
||
|
if err != nil {
|
||
|
return cert, err
|
||
|
}
|
||
|
|
||
|
cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)
|
||
|
|
||
|
return cert, err
|
||
|
}
|
||
|
|
||
|
func generateSignedCertificate(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
ca certificate,
|
||
|
) (certificate, error) {
|
||
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
|
||
|
}
|
||
|
return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
|
||
|
}
|
||
|
|
||
|
func generateSignedCertificateWithPEMKey(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
ca certificate,
|
||
|
privPEM string,
|
||
|
) (certificate, error) {
|
||
|
priv, err := parsePrivateKeyPEM(privPEM)
|
||
|
if err != nil {
|
||
|
return certificate{}, fmt.Errorf("parsing private key: %s", err)
|
||
|
}
|
||
|
return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
|
||
|
}
|
||
|
|
||
|
func generateSignedCertificateWithKeyInternal(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
ca certificate,
|
||
|
priv crypto.PrivateKey,
|
||
|
) (certificate, error) {
|
||
|
cert := certificate{}
|
||
|
|
||
|
decodedSignerCert, _ := pem.Decode([]byte(ca.Cert))
|
||
|
if decodedSignerCert == nil {
|
||
|
return cert, errors.New("unable to decode certificate")
|
||
|
}
|
||
|
signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)
|
||
|
if err != nil {
|
||
|
return cert, fmt.Errorf(
|
||
|
"error parsing certificate: decodedSignerCert.Bytes: %s",
|
||
|
err,
|
||
|
)
|
||
|
}
|
||
|
signerKey, err := parsePrivateKeyPEM(ca.Key)
|
||
|
if err != nil {
|
||
|
return cert, fmt.Errorf(
|
||
|
"error parsing private key: %s",
|
||
|
err,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
|
||
|
if err != nil {
|
||
|
return cert, err
|
||
|
}
|
||
|
|
||
|
cert.Cert, cert.Key, err = getCertAndKey(
|
||
|
template,
|
||
|
priv,
|
||
|
signerCert,
|
||
|
signerKey,
|
||
|
)
|
||
|
|
||
|
return cert, err
|
||
|
}
|
||
|
|
||
|
func getCertAndKey(
|
||
|
template *x509.Certificate,
|
||
|
signeeKey crypto.PrivateKey,
|
||
|
parent *x509.Certificate,
|
||
|
signingKey crypto.PrivateKey,
|
||
|
) (string, string, error) {
|
||
|
signeePubKey, err := getPublicKey(signeeKey)
|
||
|
if err != nil {
|
||
|
return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err)
|
||
|
}
|
||
|
derBytes, err := x509.CreateCertificate(
|
||
|
rand.Reader,
|
||
|
template,
|
||
|
parent,
|
||
|
signeePubKey,
|
||
|
signingKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return "", "", fmt.Errorf("error creating certificate: %s", err)
|
||
|
}
|
||
|
|
||
|
certBuffer := bytes.Buffer{}
|
||
|
if err := pem.Encode(
|
||
|
&certBuffer,
|
||
|
&pem.Block{Type: "CERTIFICATE", Bytes: derBytes},
|
||
|
); err != nil {
|
||
|
return "", "", fmt.Errorf("error pem-encoding certificate: %s", err)
|
||
|
}
|
||
|
|
||
|
keyBuffer := bytes.Buffer{}
|
||
|
if err := pem.Encode(
|
||
|
&keyBuffer,
|
||
|
pemBlockForKey(signeeKey),
|
||
|
); err != nil {
|
||
|
return "", "", fmt.Errorf("error pem-encoding key: %s", err)
|
||
|
}
|
||
|
|
||
|
return certBuffer.String(), keyBuffer.String(), nil
|
||
|
}
|
||
|
|
||
|
func getBaseCertTemplate(
|
||
|
cn string,
|
||
|
ips []interface{},
|
||
|
alternateDNS []interface{},
|
||
|
daysValid int,
|
||
|
) (*x509.Certificate, error) {
|
||
|
ipAddresses, err := getNetIPs(ips)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
dnsNames, err := getAlternateDNSStrs(alternateDNS)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128)
|
||
|
serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &x509.Certificate{
|
||
|
SerialNumber: serialNumber,
|
||
|
Subject: pkix.Name{
|
||
|
CommonName: cn,
|
||
|
},
|
||
|
IPAddresses: ipAddresses,
|
||
|
DNSNames: dnsNames,
|
||
|
NotBefore: time.Now(),
|
||
|
NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)),
|
||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||
|
ExtKeyUsage: []x509.ExtKeyUsage{
|
||
|
x509.ExtKeyUsageServerAuth,
|
||
|
x509.ExtKeyUsageClientAuth,
|
||
|
},
|
||
|
BasicConstraintsValid: true,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func getNetIPs(ips []interface{}) ([]net.IP, error) {
|
||
|
if ips == nil {
|
||
|
return []net.IP{}, nil
|
||
|
}
|
||
|
var ipStr string
|
||
|
var ok bool
|
||
|
var netIP net.IP
|
||
|
netIPs := make([]net.IP, len(ips))
|
||
|
for i, ip := range ips {
|
||
|
ipStr, ok = ip.(string)
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("error parsing ip: %v is not a string", ip)
|
||
|
}
|
||
|
netIP = net.ParseIP(ipStr)
|
||
|
if netIP == nil {
|
||
|
return nil, fmt.Errorf("error parsing ip: %s", ipStr)
|
||
|
}
|
||
|
netIPs[i] = netIP
|
||
|
}
|
||
|
return netIPs, nil
|
||
|
}
|
||
|
|
||
|
func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) {
|
||
|
if alternateDNS == nil {
|
||
|
return []string{}, nil
|
||
|
}
|
||
|
var dnsStr string
|
||
|
var ok bool
|
||
|
alternateDNSStrs := make([]string, len(alternateDNS))
|
||
|
for i, dns := range alternateDNS {
|
||
|
dnsStr, ok = dns.(string)
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf(
|
||
|
"error processing alternate dns name: %v is not a string",
|
||
|
dns,
|
||
|
)
|
||
|
}
|
||
|
alternateDNSStrs[i] = dnsStr
|
||
|
}
|
||
|
return alternateDNSStrs, nil
|
||
|
}
|
||
|
|
||
|
func encryptAES(password string, plaintext string) (string, error) {
|
||
|
if plaintext == "" {
|
||
|
return "", nil
|
||
|
}
|
||
|
|
||
|
key := make([]byte, 32)
|
||
|
copy(key, []byte(password))
|
||
|
block, err := aes.NewCipher(key)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
content := []byte(plaintext)
|
||
|
blockSize := block.BlockSize()
|
||
|
padding := blockSize - len(content)%blockSize
|
||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||
|
content = append(content, padtext...)
|
||
|
|
||
|
ciphertext := make([]byte, aes.BlockSize+len(content))
|
||
|
|
||
|
iv := ciphertext[:aes.BlockSize]
|
||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||
|
mode.CryptBlocks(ciphertext[aes.BlockSize:], content)
|
||
|
|
||
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||
|
}
|
||
|
|
||
|
func decryptAES(password string, crypt64 string) (string, error) {
|
||
|
if crypt64 == "" {
|
||
|
return "", nil
|
||
|
}
|
||
|
|
||
|
key := make([]byte, 32)
|
||
|
copy(key, []byte(password))
|
||
|
|
||
|
crypt, err := base64.StdEncoding.DecodeString(crypt64)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
block, err := aes.NewCipher(key)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
iv := crypt[:aes.BlockSize]
|
||
|
crypt = crypt[aes.BlockSize:]
|
||
|
decrypted := make([]byte, len(crypt))
|
||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||
|
mode.CryptBlocks(decrypted, crypt)
|
||
|
|
||
|
return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil
|
||
|
}
|