You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
4.2 KiB
Go
218 lines
4.2 KiB
Go
package service
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"io/ioutil"
|
|
"net/http"
|
|
)
|
|
|
|
import "golang.org/x/crypto/blowfish"
|
|
|
|
type Status int
|
|
|
|
const (
|
|
OK Status = iota
|
|
WAITING
|
|
ERROR
|
|
)
|
|
|
|
type BaseMessage struct {
|
|
Signature string
|
|
}
|
|
|
|
type httpServer struct {
|
|
manager *Manager
|
|
status Status
|
|
}
|
|
|
|
type CreateCSRRequest struct {
|
|
*BaseMessage
|
|
Hostname string
|
|
}
|
|
|
|
type CreateCSRResponse struct {
|
|
*BaseMessage
|
|
CSR string `json:"csr"`
|
|
}
|
|
|
|
type UpdateOpenVPNConfigRequest struct {
|
|
*BaseMessage
|
|
Config string
|
|
}
|
|
|
|
type DeliverCertificateRequest struct {
|
|
*BaseMessage
|
|
Certificate string
|
|
}
|
|
|
|
func NewHttpServer(manager *Manager) *httpServer {
|
|
return &httpServer{manager, WAITING}
|
|
}
|
|
|
|
func (it *httpServer) Start() {
|
|
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
|
writer.WriteHeader(200)
|
|
writer.Write([]byte("Don't"))
|
|
})
|
|
|
|
http.HandleFunc("/create-csr", func(writer http.ResponseWriter, request *http.Request) {
|
|
req := &CreateCSRRequest{}
|
|
err := it.verifyRequest(request, req)
|
|
|
|
if err != nil {
|
|
writer.WriteHeader(400)
|
|
return
|
|
}
|
|
|
|
csr, err := it.manager.CreateCSR(req.Hostname)
|
|
if err != nil {
|
|
writer.WriteHeader(500)
|
|
return
|
|
}
|
|
|
|
it.writeResponse(writer, CreateCSRResponse{
|
|
CSR: string(csr),
|
|
})
|
|
})
|
|
|
|
http.HandleFunc("/deliver-crt", func(writer http.ResponseWriter, request *http.Request) {
|
|
req := &DeliverCertificateRequest{}
|
|
err := it.verifyRequest(request, req)
|
|
if err != nil {
|
|
writer.WriteHeader(400)
|
|
return
|
|
}
|
|
|
|
err = it.manager.UpdateCertificate(req.Certificate)
|
|
if err != nil {
|
|
writer.WriteHeader(500)
|
|
return
|
|
}
|
|
|
|
it.manager.openVPN.Start()
|
|
})
|
|
|
|
http.HandleFunc("/update-openvpn-config", func(writer http.ResponseWriter, request *http.Request) {
|
|
req := &UpdateOpenVPNConfigRequest{}
|
|
err := it.verifyRequest(request, req)
|
|
if err != nil {
|
|
writer.WriteHeader(400)
|
|
return
|
|
}
|
|
|
|
err = it.manager.openVPN.UpdateConfig(req.Config)
|
|
if err != nil {
|
|
writer.WriteHeader(500)
|
|
return
|
|
}
|
|
|
|
it.manager.openVPN.Restart()
|
|
})
|
|
|
|
http.ListenAndServe(":7864", nil)
|
|
}
|
|
|
|
func (it *httpServer) writeResponse(writer http.ResponseWriter, v interface{}) error {
|
|
passwordAndIV := make([]byte, 48)
|
|
_, err := rand.Read(passwordAndIV)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
encPasswordAndIV, err := rsa.EncryptPKCS1v15(rand.Reader, it.manager.CAPublicKey(), passwordAndIV)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = writer.Write([]byte(hex.EncodeToString(encPasswordAndIV)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
password := passwordAndIV[:32]
|
|
iv := passwordAndIV[32:]
|
|
|
|
cipher, err := blowfish.NewSaltedCipher(password, iv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hashedFingerpint := sha256.Sum256(it.manager.GetServerFingerprint())
|
|
plainSignature, err := rsa.SignPKCS1v15(rand.Reader, it.manager.privateKey, 0, hashedFingerpint[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sign, ok := v.(*BaseMessage)
|
|
if !ok {
|
|
return errors.New("Given message can't be signed")
|
|
}
|
|
sign.Signature = hex.EncodeToString(plainSignature)
|
|
|
|
body, err := json.Marshal(v)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
encBody := make([]byte, len(body))
|
|
cipher.Encrypt(encBody, body)
|
|
writer.Write([]byte(hex.EncodeToString(encBody)))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (it *httpServer) verifyRequest(r *http.Request, v interface{}) (error) {
|
|
all, err := ioutil.ReadAll(hex.NewDecoder(r.Body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
encPasswordAndIV := all[:256]
|
|
encBody := all[256:]
|
|
|
|
passwordAndIV, err := rsa.DecryptPKCS1v15(rand.Reader, it.manager.privateKey, encPasswordAndIV)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
password := passwordAndIV[:32]
|
|
iv := passwordAndIV[32:]
|
|
|
|
cipher, err := blowfish.NewSaltedCipher(password, iv)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
body := make([]byte, len(encBody))
|
|
cipher.Decrypt(body, encBody)
|
|
|
|
err = json.Unmarshal(body, v)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
baseReq, ok := v.(*BaseMessage)
|
|
if !ok {
|
|
return errors.New("non-base request")
|
|
}
|
|
|
|
signature, err := hex.DecodeString(baseReq.Signature)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fingerprint := it.manager.GetServerFingerprint()
|
|
fingerprintHashed := sha256.Sum256(fingerprint)
|
|
err = rsa.VerifyPKCS1v15(it.manager.CAPublicKey(), 0, fingerprintHashed[:], signature)
|
|
return err
|
|
}
|