forked from Ne0nd0g/merlin
/
tls.go
125 lines (104 loc) · 3.84 KB
/
tls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Merlin is a post-exploitation command and control framework.
// This file is part of Merlin.
// Copyright (C) 2019 Russel Van Tuyl
// Merlin is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
// Merlin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Merlin. If not, see <http://www.gnu.org/licenses/>.
package util
import (
// Standard
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"math/big"
"time"
)
/*
GenerateTLSCert will generate a new certificate. Nil values in the parameters are replaced with random or blank values.
If makeRsa is set to true, the key generated is an RSA key (EC by default).
If a nil date is passed in for notBefore and notAfter, a random date is picked in the last year.
If a nil date is passed in for notAfter, the date is set to be 2 years after the date provided (or generated) in the notBefore parameter.
Please ensure privkey is a proper private key. The go implementation of this value is challenging, so no type assertion can be made in the function definition.
*/
func GenerateTLSCert(serial *big.Int, subject *pkix.Name, dnsNames []string, notBefore, notAfter *time.Time, privKey crypto.PrivateKey, makeRsa bool) (*tls.Certificate, error) {
//https://golang.org/src/crypto/tls/generate_cert.go taken from here mostly
var err error
if serial == nil {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) //128 bits tops
serial, err = rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
}
}
if subject == nil { //pointers make it easier to compare to nils
subject = &pkix.Name{} //todo: generate random subject attributes?
}
//todo: generate random names?
if notBefore == nil {
randDay, err := rand.Int(rand.Reader, big.NewInt(360)) //not 365, playing it safe... time and computers are hard
if err != nil {
return nil, err
}
b4 := time.Now().AddDate(0, 0, -1*int(randDay.Int64())) //random date sometime in the last year
notBefore = &b4
}
if notAfter == nil {
aft := notBefore.AddDate(2, 0, 0) //2 years after the notbefore date
notAfter = &aft
}
tpl := x509.Certificate{
SerialNumber: serial,
Subject: *subject,
DNSNames: dnsNames,
NotBefore: *notBefore,
NotAfter: *notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
if privKey == nil {
if makeRsa {
privKey, err = rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, err
}
} else {
privKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) //maybe check to see if P384 is the right choice (would want to be the most common choice for ec curves)
if err != nil {
return nil, err
}
}
}
crtBytes, err := x509.CreateCertificate(rand.Reader, &tpl, &tpl, getPublicKey(privKey), privKey)
if err != nil {
return nil, err
}
return &tls.Certificate{
Certificate: [][]byte{crtBytes},
PrivateKey: privKey,
}, nil
}
//getPublicKey takes in a private key, and provides the public key from it.
//https://golang.org/src/crypto/tls/generate_cert.go
func getPublicKey(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return nil
}
}