-
-
Save dpb587-pivotal/d0d132c586ed4053323b4d4246664a07 to your computer and use it in GitHub Desktop.
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
#!/bin/bash | |
func build() { | |
build_dir=/tmp/padding-bug/build | |
openssl_version=$1 | |
install_dir=$2 | |
lzo_version=2.10 | |
openvpn_version=2.4.7 | |
mkdir -p ${build_dir} | |
pushd ${build_dir} | |
wget -qO https://www.openssl.org/source/openssl-${openssl_version}.tar.gz | tar -xzf- | |
pushd openssl-* | |
./config \ | |
-DSSL_ALLOW_ADH \ | |
--shared \ | |
--prefix=${install_dir}/external/openssl \ | |
--openssldir=${install_dir}/external/openssldir | |
make | |
make install | |
popd | |
wget -qO https://www.oberhumer.com/opensource/lzo/download/lzo-${lzo_version}.tar.gz | tar -xzf- | |
pushd lzo-* | |
./configure \ | |
--prefix=${install_dir}/external/lzo | |
make | |
make install | |
popd | |
wget -qO https://swupdate.openvpn.org/community/releases/openvpn-${openvpn_version}.tar.gz | tar -xzf- | |
pushd openvpn-* | |
export CFLAGS="-I${install_dir}/external/openssl/include -Wl,-rpath ${install_dir}/external/openssl/lib -L${install_dir}/external/openssl/lib" | |
export LZO_CFLAGS="-I${install_dir}/external/lzo/include" | |
export LZO_LIBS="-L${install_dir}/external/lzo/lib -llzo2" | |
./configure \ | |
--prefix=${install_dir} \ | |
--disable-plugin-auth-pam | |
make | |
make install | |
popd | |
popd | |
rm -fr ${build_dir} | |
} | |
build 1.1.0l ~/tmp/padding-bug/with-openssl-1.1.0 | |
~/tmp/padding-bug/with-openssl-1.1.0/sbin/openvpn --version | |
# OpenVPN 2.4.7 x86_64-apple-darwin18.7.0 [SSL (OpenSSL)] [LZO] [LZ4] [MH/RECVDA] [AEAD] built on Sep 20 2019 | |
# library versions: OpenSSL 1.1.0l 10 Sep 2019, LZO 2.10 | |
# Originally developed by James Yonan | |
# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> | |
# Compile time defines: enable_async_push=no enable_comp_stub=no enable_crypto=yes enable_crypto_ofb_cfb=yes enable_debug=yes enable_def_auth=yes enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown enable_fast_install=needless enable_fragment=yes enable_iproute2=no enable_libtool_lock=yes enable_lz4=yes enable_lzo=yes enable_management=yes enable_multihome=yes enable_pam_dlopen=no enable_pedantic=no enable_pf=yes enable_pkcs11=no enable_plugin_auth_pam=no enable_plugin_down_root=yes enable_plugins=yes enable_port_share=yes enable_selinux=no enable_server=yes enable_shared=yes enable_shared_with_static_runtimes=no enable_small=no enable_static=yes enable_strict=no enable_strict_options=no enable_systemd=no enable_werror=no enable_win32_dll=yes enable_x509_alt_username=no with_aix_soname=aix with_crypto_library=openssl with_gnu_ld=no with_mem_check=no with_sysroot=no | |
build 1.1.1d ~/tmp/padding-bug/with-openssl-1.1.1 | |
~/tmp/padding-bug/with-openssl-1.1.1/sbin/openvpn --version | |
# OpenVPN 2.4.7 x86_64-apple-darwin18.7.0 [SSL (OpenSSL)] [LZO] [LZ4] [MH/RECVDA] [AEAD] built on Sep 20 2019 | |
# library versions: OpenSSL 1.1.1d 10 Sep 2019, LZO 2.10 | |
# Originally developed by James Yonan | |
# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> | |
# Compile time defines: enable_async_push=no enable_comp_stub=no enable_crypto=yes enable_crypto_ofb_cfb=yes enable_debug=yes enable_def_auth=yes enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown enable_fast_install=needless enable_fragment=yes enable_iproute2=no enable_libtool_lock=yes enable_lz4=yes enable_lzo=yes enable_management=yes enable_multihome=yes enable_pam_dlopen=no enable_pedantic=no enable_pf=yes enable_pkcs11=no enable_plugin_auth_pam=no enable_plugin_down_root=yes enable_plugins=yes enable_port_share=yes enable_selinux=no enable_server=yes enable_shared=yes enable_shared_with_static_runtimes=no enable_small=no enable_static=yes enable_strict=no enable_strict_options=no enable_systemd=no enable_werror=no enable_win32_dll=yes enable_x509_alt_username=no with_aix_soname=aix with_crypto_library=openssl with_gnu_ld=no with_mem_check=no with_sysroot=no |
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
package main | |
import ( | |
"bufio" | |
"bytes" | |
"crypto/rand" | |
"crypto/rsa" | |
"crypto/x509" | |
"encoding/base64" | |
"encoding/pem" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net" | |
"os" | |
"strings" | |
"github.com/dpb587/go-openvpn/ovpn" | |
"github.com/pkg/errors" | |
) | |
var managementAddress = "127.0.0.1:12913" | |
func main() { | |
data, err := ioutil.ReadFile(os.Args[1]) | |
if err != nil { | |
panic(errors.Wrap(err, "reading profile")) | |
} | |
profile, err := ovpn.Parse(data) | |
if err != nil { | |
panic(errors.Wrap(err, "parsing profile")) | |
} | |
switch os.Args[2] { | |
case "profile": | |
fmt.Printf("%s", createManagedProfile(profile, managementAddress)) | |
case "management": | |
err = startManagementServer(managementAddress, profile) | |
if err != nil { | |
panic(err) | |
} | |
default: | |
panic(fmt.Errorf("unexpected command: %s", os.Args[2])) | |
} | |
} | |
func createManagedProfile(profile *ovpn.Profile, managementAddress string) []byte { | |
w := &bytes.Buffer{} | |
for _, e := range profile.Elements { | |
switch pe := e.(type) { | |
case ovpn.DirectiveProfileElement: | |
fmt.Fprintf(w, "%s %s\n", pe.Directive(), strings.Join(pe.Args(), " ")) | |
case ovpn.EmbeddedProfileElement: | |
switch pe.Embed() { | |
case "cert", "key": | |
// ignore; handled via management | |
default: | |
fmt.Fprintf(w, "<%s>\n%s</%s>\n", pe.Embed(), pe.Data(), pe.Embed()) | |
} | |
} | |
} | |
fmt.Fprintf(w, "management %s\n", strings.Join(strings.Split(managementAddress, ":"), " ")) | |
fmt.Fprintf(w, "management-client\n") | |
fmt.Fprintf(w, "management-external-cert ssoca\n") | |
fmt.Fprintf(w, "management-external-key\n") | |
return w.Bytes() | |
} | |
func startManagementServer(managementAddress string, profile *ovpn.Profile) error { | |
listener, err := net.Listen("tcp", managementAddress) | |
if err != nil { | |
return errors.Wrap(err, "binding") | |
} | |
conn, err := listener.Accept() | |
defer listener.Close() | |
if err != nil { | |
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { | |
return nil | |
} | |
return err | |
} | |
log.Printf("new openvpn management connection (%s)", conn.RemoteAddr().String()) | |
err = handleManagementConnection(conn, profile) | |
if err != nil { | |
panic(err) | |
} | |
return nil | |
} | |
func handleManagementConnection(conn net.Conn, profile *ovpn.Profile) error { | |
defer conn.Close() | |
certPEM := profile.GetEmbedded("cert")[0].(ovpn.EmbeddedProfileElement).Data() | |
block, _ := pem.Decode([]byte(profile.GetEmbedded("key")[0].(ovpn.EmbeddedProfileElement).Data())) | |
if block == nil { | |
return errors.New("no private key found") | |
} | |
privRSA, err := x509.ParsePKCS1PrivateKey(block.Bytes) | |
if err != nil { | |
return errors.Wrap(err, "parsing key from profile") | |
} | |
reader := bufio.NewReader(conn) | |
for { | |
log.Print("openvpn management waiting for data") | |
message, err := reader.ReadString('\n') | |
if err != nil { | |
return err | |
} | |
log.Printf("openvpn management data recv: %s", message) | |
var keepGoing bool | |
if strings.HasPrefix(message, ">") { | |
keepGoing = func(message string) bool { | |
split := strings.SplitN(message, ":", 2) | |
if len(split) != 2 { | |
fmt.Println(fmt.Errorf("unexpected realtime message: %s", message)) | |
return true | |
} | |
var err error | |
messageSource, messageText := split[0], split[1][0:len(split[1])-1] | |
switch messageSource { | |
case "INFO": | |
log.Print(messageText) | |
case "NEED-CERTIFICATE": | |
conn.Write([]byte("certificate\n")) | |
conn.Write([]byte(certPEM)) | |
conn.Write([]byte("\n")) | |
conn.Write([]byte("END\n")) | |
case "RSA_SIGN": | |
data64, err := base64.StdEncoding.DecodeString(messageText) | |
if err != nil { | |
log.Fatal(errors.Wrap(err, "decoding signing token")) | |
} | |
signature, err := rsa.SignPKCS1v15(rand.Reader, privRSA, 0, data64) | |
if err != nil { | |
log.Fatal(errors.Wrap(err, "signing token")) | |
} | |
signature64 := base64.StdEncoding.EncodeToString(signature) | |
conn.Write([]byte("rsa-sig")) | |
conn.Write([]byte("\n")) | |
conn.Write([]byte(signature64)) | |
conn.Write([]byte("\n")) | |
conn.Write([]byte("END\n")) | |
default: | |
log.Printf("unexpected realtime message: %s", messageSource) | |
} | |
if err != nil { | |
log.Printf("unexpected error: %s", err) | |
conn.Write([]byte("signal SIGTERM\n")) | |
} | |
return true | |
}(message[1:]) | |
} else { | |
keepGoing = true | |
log.Print(message) | |
} | |
if !keepGoing { | |
log.Print("openvpn management exiting loop") | |
break | |
} | |
} | |
return 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
#!/bin/bash | |
go get gist.github.com/dpb587-pivotal/d0d132c586ed4053323b4d4246664a07.git | |
go build -o ~/tmp/padding-bug/management-tool gist.github.com/dpb587-pivotal/d0d132c586ed4053323b4d4246664a07.git |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment