github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4openvpn/messages.go (about)

     1  // Copyright 2024 VNXME
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package l4openvpn
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/base64"
    20  	"encoding/binary"
    21  	"errors"
    22  	"slices"
    23  	"time"
    24  )
    25  
    26  // MessageHeader is an OpenVPN message header.
    27  type MessageHeader struct {
    28  	// Opcode is a type of message that follows.
    29  	Opcode uint8
    30  	// KeyID refers to an already negotiated TLS session. It must equal zero for client reset messages.
    31  	KeyID uint8
    32  }
    33  
    34  // FromBytes fills msg's internal structures from source bytes.
    35  func (msg *MessageHeader) FromBytes(src []byte) error {
    36  	// Any MessageHeader has exactly 1 byte.
    37  	if len(src) != OpcodeKeyIDBytesTotal {
    38  		return ErrInvalidSourceLength
    39  	}
    40  
    41  	// Opcode occupies the high 5 bits, KeyID extends over the low 3 bits.
    42  	msg.KeyID, msg.Opcode = src[0]&KeyIDMask, src[0]>>OpcodeShift
    43  
    44  	return nil
    45  }
    46  
    47  // ToBytes return a slice of bytes representing msg's internal structures.
    48  func (msg *MessageHeader) ToBytes() []byte {
    49  	dst := make([]byte, 0, OpcodeKeyIDBytesTotal)
    50  	dst = append(dst, msg.KeyID|(msg.Opcode<<OpcodeShift))
    51  	return dst
    52  }
    53  
    54  // MessagePlain is a P_CONTROL_HARD_RESET_CLIENT_V2-type OpenVPN message with no authentication.
    55  type MessagePlain struct {
    56  	MessageHeader
    57  
    58  	// LocalSessionID contains an 8-byte session ID assigned on the client. It must be non-zero.
    59  	LocalSessionID uint64
    60  	// PrevPacketIDsCount indicates how many previous packet IDs will follow. It must equal zero.
    61  	PrevPacketIDsCount uint8
    62  	// ThisPacketID contains a 4-byte packet ID of the current message. It must equal zero.
    63  	ThisPacketID uint32
    64  }
    65  
    66  // FromBytes fills msg's internal structures from a slice of bytes.
    67  func (msg *MessagePlain) FromBytes(src []byte) error {
    68  	// Any MessagePlain is exactly 14 bytes (with a header).
    69  	if len(src) != MessagePlainBytesTotal {
    70  		return ErrInvalidSourceLength
    71  	}
    72  
    73  	// Parse MessageHeader
    74  	hdr := &MessageHeader{}
    75  	if err := hdr.FromBytes(src[:OpcodeKeyIDBytesTotal]); err != nil {
    76  		return err
    77  	}
    78  
    79  	// Match MessageHeader.Opcode
    80  	if hdr.Opcode != OpcodeControlHardResetClientV2 {
    81  		return ErrInvalidHeaderOpcode
    82  	}
    83  
    84  	// Parse everything else
    85  	return msg.FromBytesHeadless(src[OpcodeKeyIDBytesTotal:], hdr)
    86  }
    87  
    88  // FromBytesHeadless fills msg's internal structures from a slice of bytes and uses a pre-filled header.
    89  func (msg *MessagePlain) FromBytesHeadless(src []byte, hdr *MessageHeader) error {
    90  
    91  	// Any MessagePlain is exactly 13 bytes long (without a header).
    92  	if len(src) != MessagePlainBytesTotalHL {
    93  		return ErrInvalidSourceLength
    94  	}
    95  
    96  	// Check for a non-empty MessageHeader.
    97  	if hdr == nil {
    98  		return ErrMissingReusableHeader
    99  	}
   100  
   101  	// Assign Header to the specified pointer.
   102  	msg.MessageHeader = *hdr
   103  
   104  	// Any MessagePlain has an 8-byte LocalSessionID at the beginning.
   105  	msg.LocalSessionID = BytesOrder.Uint64(src[:SessionIDBytesTotal])
   106  
   107  	// Any MessagePlain has a 1-byte PrevPacketIDsCount between LocalSessionID and ThisPacketID.
   108  	msg.PrevPacketIDsCount = src[SessionIDBytesTotal]
   109  
   110  	// Any MessagePlain has a 4-byte ThisPacketID at the end.
   111  	msg.ThisPacketID = BytesOrder.Uint32(src[len(src)-PacketIDBytesTotal:])
   112  
   113  	return nil
   114  }
   115  
   116  // Match returns true if msg's internal structures have valid values.
   117  func (msg *MessagePlain) Match() bool {
   118  	return msg.LocalSessionID > 0 && msg.PrevPacketIDsCount == 0 && msg.ThisPacketID == 0
   119  }
   120  
   121  // ToBytes return a slice of bytes representing msg's internal structures.
   122  func (msg *MessagePlain) ToBytes() []byte {
   123  	dst := make([]byte, 0, MessagePlainBytesTotal)
   124  	dst = append(dst, msg.MessageHeader.ToBytes()...)
   125  	dst = BytesOrder.AppendUint64(dst, msg.LocalSessionID)
   126  	dst = append(dst, msg.PrevPacketIDsCount)
   127  	dst = BytesOrder.AppendUint32(dst, msg.ThisPacketID)
   128  	return dst
   129  }
   130  
   131  // MessageAuth is a P_CONTROL_HARD_RESET_CLIENT_V2-type OpenVPN message with authentication.
   132  type MessageAuth struct {
   133  	MessagePlain
   134  	MessageTraitAuth
   135  	MessageTraitReplay
   136  }
   137  
   138  // Authenticate returns true if msg has a valid HMAC.
   139  func (msg *MessageAuth) Authenticate(ad *AuthDigest, sk *StaticKey) bool {
   140  	return msg.MessageTraitAuth.AuthenticateOnServer(ad, sk, msg.ToBytesAuth)
   141  }
   142  
   143  // FromBytes fills msg's internal structures from a slice of bytes.
   144  func (msg *MessageAuth) FromBytes(src []byte) error {
   145  	// Any MessageAuth is between 38 and 86 bytes (with a header).
   146  	if len(src) < MessageAuthBytesMin || len(src) > MessageAuthBytesMax {
   147  		return ErrInvalidSourceLength
   148  	}
   149  
   150  	// Parse MessageHeader
   151  	hdr := &MessageHeader{}
   152  	if err := hdr.FromBytes(src[:OpcodeKeyIDBytesTotal]); err != nil {
   153  		return err
   154  	}
   155  
   156  	// Match MessageHeader.Opcode
   157  	if hdr.Opcode != OpcodeControlHardResetClientV2 {
   158  		return ErrInvalidHeaderOpcode
   159  	}
   160  
   161  	// Parse everything else
   162  	return msg.FromBytesHeadless(src[OpcodeKeyIDBytesTotal:], hdr)
   163  }
   164  
   165  // FromBytesHeadless fills msg's internal structures from a slice of bytes and uses a pre-filled header.
   166  func (msg *MessageAuth) FromBytesHeadless(src []byte, hdr *MessageHeader) error {
   167  	// Any MessageAuth is between 37 and 85 bytes long (without a header).
   168  	if len(src) < MessageAuthBytesMinHL || len(src) > MessageAuthBytesMaxHL {
   169  		return ErrInvalidSourceLength
   170  	}
   171  
   172  	// Check for a non-empty MessageHeader.
   173  	if hdr == nil {
   174  		return ErrMissingReusableHeader
   175  	}
   176  
   177  	// Assign Header to the specified pointer.
   178  	msg.MessageHeader = *hdr
   179  
   180  	// Any MessageAuth has an 8-byte LocalSessionID at the beginning.
   181  	msg.LocalSessionID = BytesOrder.Uint64(src[:SessionIDBytesTotal])
   182  
   183  	// Any MessageAuth has a 16-to-64-byte HMAC between LocalSessionID and ReplayPacketID.
   184  	off1, off2 := SessionIDBytesTotal, len(src)-2*PacketIDBytesTotal-OpcodeKeyIDBytesTotal-TimestampBytesTotal
   185  	msg.HMAC = src[off1:off2]
   186  
   187  	// Check whether a valid HMAC length is provided.
   188  	if !slices.Contains(AuthDigestSizes, len(msg.HMAC)) {
   189  		return ErrInvalidHMACLength
   190  	}
   191  
   192  	// Any MessageAuth has a 4-byte ReplayPacketID between HMAC and ReplayTimestamp.
   193  	off1, off2 = off2, off2+PacketIDBytesTotal
   194  	msg.ReplayPacketID = BytesOrder.Uint32(src[off1:off2])
   195  
   196  	// Any MessageAuth has a 4-byte ReplayTimestamp between ReplayPacketID and PrevPacketIDsCount.
   197  	off1, off2 = off2, off2+TimestampBytesTotal
   198  	msg.ReplayTimestamp = BytesOrder.Uint32(src[off1:off2])
   199  
   200  	// Any MessageAuth has a 1-byte PrevPacketIDsCount between ReplayTimestamp and ThisPacketID.
   201  	off1, off2 = off2, off2+OpcodeKeyIDBytesTotal
   202  	msg.PrevPacketIDsCount = src[off1]
   203  
   204  	// Any MessageAuth has a 4-byte ThisPacketID at the end.
   205  	msg.ThisPacketID = BytesOrder.Uint32(src[off2:])
   206  
   207  	return nil
   208  }
   209  
   210  // Match returns true if msg's internal structures have valid values.
   211  func (msg *MessageAuth) Match(ignoreTimestamp, ignoreCrypto bool, ad *AuthDigest, sk *StaticKey) bool {
   212  	return msg.MessagePlain.Match() &&
   213  		msg.ReplayPacketID == 1 && (ignoreTimestamp || msg.ValidateReplayTimestamp(time.Now())) &&
   214  		(ad == nil || ad.Size == len(msg.MessageTraitAuth.HMAC)) &&
   215  		(ignoreCrypto || sk == nil || msg.Authenticate(ad, sk))
   216  }
   217  
   218  // Sign computes and fills msg's HMAC.
   219  func (msg *MessageAuth) Sign(ad *AuthDigest, sk *StaticKey) error {
   220  	return msg.MessageTraitAuth.SignOnClient(ad, sk, msg.ToBytesAuth)
   221  }
   222  
   223  // ToBytes returns a slice of bytes representing msg's internal structures.
   224  func (msg *MessageAuth) ToBytes() []byte {
   225  	dst := make([]byte, 0, MessagePlainBytesTotal+len(msg.HMAC)+PacketIDBytesTotal+TimestampBytesTotal)
   226  	dst = append(dst, msg.MessageHeader.ToBytes()...)
   227  	dst = BytesOrder.AppendUint64(dst, msg.LocalSessionID)
   228  	dst = append(dst, msg.HMAC...)
   229  	dst = BytesOrder.AppendUint32(dst, msg.ReplayPacketID)
   230  	dst = BytesOrder.AppendUint32(dst, msg.ReplayTimestamp)
   231  	dst = append(dst, msg.PrevPacketIDsCount)
   232  	dst = BytesOrder.AppendUint32(dst, msg.ThisPacketID)
   233  	return dst
   234  }
   235  
   236  // ToBytesAuth returns a slice of bytes representing msg's internal structures without HMAC.
   237  func (msg *MessageAuth) ToBytesAuth() []byte {
   238  	dst := make([]byte, 0, MessagePlainBytesTotal+PacketIDBytesTotal+TimestampBytesTotal)
   239  	dst = BytesOrder.AppendUint32(dst, msg.ReplayPacketID)
   240  	dst = BytesOrder.AppendUint32(dst, msg.ReplayTimestamp)
   241  	dst = append(dst, msg.MessageHeader.ToBytes()...)
   242  	dst = BytesOrder.AppendUint64(dst, msg.LocalSessionID)
   243  	dst = append(dst, msg.PrevPacketIDsCount)
   244  	dst = BytesOrder.AppendUint32(dst, msg.ThisPacketID)
   245  	return dst
   246  }
   247  
   248  // MessageCrypt is a P_CONTROL_HARD_RESET_CLIENT_V2-type OpenVPN message with authentication and encryption.
   249  type MessageCrypt struct {
   250  	MessageAuth
   251  	MessageTraitCrypt
   252  }
   253  
   254  // Authenticate returns true if msg has a valid HMAC.
   255  func (msg *MessageCrypt) Authenticate(ad *AuthDigest, sk *StaticKey) bool {
   256  	return msg.MessageTraitAuth.AuthenticateOnServer(ad, sk, msg.ToBytesAuth)
   257  }
   258  
   259  // DecryptAndAuthenticate decrypts msg's encrypted bytes before calling Authenticate.
   260  func (msg *MessageCrypt) DecryptAndAuthenticate(ad *AuthDigest, sk *StaticKey) bool {
   261  	if len(msg.Encrypted) != OpcodeKeyIDBytesTotal+PacketIDBytesTotal ||
   262  		msg.MessageTraitCrypt.DecryptOnServer(sk, &msg.MessageTraitAuth, msg.FromBytesCrypt) != nil {
   263  		return false
   264  	}
   265  	return msg.Authenticate(ad, sk)
   266  }
   267  
   268  // EncryptAndSign encrypts msg's plain bytes before calling Sign.
   269  func (msg *MessageCrypt) EncryptAndSign(ad *AuthDigest, sk *StaticKey) error {
   270  	if err := msg.MessageTraitCrypt.EncryptOnClient(sk, &msg.MessageTraitAuth, msg.ToBytesCrypt); err != nil {
   271  		return err
   272  	}
   273  	return msg.Sign(ad, sk)
   274  }
   275  
   276  // FromBytes fills msg's internal structures from a slice of bytes.
   277  func (msg *MessageCrypt) FromBytes(src []byte) error {
   278  	// Any MessageCrypt is between 54 bytes (with a header).
   279  	if len(src) != MessageCryptBytesTotal {
   280  		return ErrInvalidSourceLength
   281  	}
   282  
   283  	// Parse MessageHeader
   284  	hdr := &MessageHeader{}
   285  	if err := hdr.FromBytes(src[:OpcodeKeyIDBytesTotal]); err != nil {
   286  		return err
   287  	}
   288  
   289  	// Match MessageHeader.Opcode
   290  	if hdr.Opcode != OpcodeControlHardResetClientV2 {
   291  		return ErrInvalidHeaderOpcode
   292  	}
   293  
   294  	// Parse everything else
   295  	return msg.FromBytesHeadless(src[OpcodeKeyIDBytesTotal:], hdr)
   296  }
   297  
   298  // FromBytesHeadless fills msg's internal structures from a slice of bytes and uses a pre-filled header.
   299  func (msg *MessageCrypt) FromBytesHeadless(src []byte, hdr *MessageHeader) error {
   300  	// Any MessageCrypt is exactly 53 bytes long (without a header).
   301  	if len(src) != MessageCryptBytesTotalHL {
   302  		return ErrInvalidSourceLength
   303  	}
   304  
   305  	// Check for a non-empty MessageHeader.
   306  	if hdr == nil {
   307  		return ErrMissingReusableHeader
   308  	}
   309  
   310  	// Assign Header to the specified pointer.
   311  	msg.MessageHeader = *hdr
   312  
   313  	// Any MessageCrypt has an 8-byte LocalSessionID at the beginning.
   314  	msg.LocalSessionID = BytesOrder.Uint64(src[:SessionIDBytesTotal])
   315  
   316  	// Any MessageCrypt has a 4-byte ReplayPacketID between LocalSessionID and ReplayTimestamp.
   317  	off1, off2 := SessionIDBytesTotal, SessionIDBytesTotal+PacketIDBytesTotal
   318  	msg.ReplayPacketID = BytesOrder.Uint32(src[off1:off2])
   319  
   320  	// Any MessageCrypt has a 4-byte ReplayTimestamp between ReplayPacketID and HMAC.
   321  	off1, off2 = off2, off2+TimestampBytesTotal
   322  	msg.ReplayTimestamp = BytesOrder.Uint32(src[off1:off2])
   323  
   324  	// Any MessageCrypt has a 32-byte SHA-256 HMAC between ReplayTimestamp and Encrypted bytes.
   325  	off1, off2 = off2, off2+AuthDigestDefault.Size
   326  	msg.Digest, msg.HMAC = AuthDigestDefault, src[off1:off2]
   327  
   328  	// Any MessageCrypt has a 5-byte Encrypted part at the end.
   329  	msg.Cipher, msg.Encrypted = CryptCipherDefault, src[off2:]
   330  
   331  	return nil
   332  }
   333  
   334  // FromBytesCrypt fills msg's internal structures from a slice of bytes after decryption.
   335  func (msg *MessageCrypt) FromBytesCrypt(plain []byte) error {
   336  	if len(plain) != len(msg.Encrypted) {
   337  		return ErrInvalidPlainLength
   338  	}
   339  
   340  	// Any MessageCrypt has a PrevPacketIDsCount at the beginning of the plain text.
   341  	msg.PrevPacketIDsCount = plain[0]
   342  
   343  	// Any MessageCrypt has a ThisPacketID at the end of the plain text.
   344  	msg.ThisPacketID = BytesOrder.Uint32(plain[OpcodeKeyIDBytesTotal:])
   345  
   346  	return nil
   347  }
   348  
   349  // Match returns true if msg's internal structures have valid values.
   350  func (msg *MessageCrypt) Match(ignoreTimestamp, ignoreCrypto bool, ad *AuthDigest, sk *StaticKey) bool {
   351  	return msg.LocalSessionID > 0 &&
   352  		msg.ReplayPacketID == 1 && (ignoreTimestamp || msg.ValidateReplayTimestamp(time.Now())) &&
   353  		(ignoreCrypto || sk == nil || (msg.DecryptAndAuthenticate(ad, sk) &&
   354  			msg.PrevPacketIDsCount == 0 && msg.ThisPacketID == 0))
   355  }
   356  
   357  // Sign computes and fills msg's HMAC.
   358  func (msg *MessageCrypt) Sign(ad *AuthDigest, sk *StaticKey) error {
   359  	return msg.MessageTraitAuth.SignOnClient(ad, sk, msg.ToBytesAuth)
   360  }
   361  
   362  // ToBytes returns a slice of bytes representing msg's internal structures.
   363  func (msg *MessageCrypt) ToBytes() []byte {
   364  	dst := make([]byte, 0, MessagePlainBytesTotal+len(msg.HMAC)+PacketIDBytesTotal+TimestampBytesTotal)
   365  	dst = append(dst, msg.MessageHeader.ToBytes()...)
   366  	dst = BytesOrder.AppendUint64(dst, msg.LocalSessionID)
   367  	dst = BytesOrder.AppendUint32(dst, msg.ReplayPacketID)
   368  	dst = BytesOrder.AppendUint32(dst, msg.ReplayTimestamp)
   369  	dst = append(dst, msg.HMAC...)
   370  	dst = append(dst, msg.Encrypted...)
   371  	return dst
   372  }
   373  
   374  // ToBytesAuth returns a slice of bytes representing msg's internal structures without HMAC.
   375  func (msg *MessageCrypt) ToBytesAuth() []byte {
   376  	dst := make([]byte, 0, MessagePlainBytesTotal+PacketIDBytesTotal+TimestampBytesTotal)
   377  	dst = append(dst, msg.MessageHeader.ToBytes()...)
   378  	dst = BytesOrder.AppendUint64(dst, msg.LocalSessionID)
   379  	dst = BytesOrder.AppendUint32(dst, msg.ReplayPacketID)
   380  	dst = BytesOrder.AppendUint32(dst, msg.ReplayTimestamp)
   381  	dst = append(dst, msg.PrevPacketIDsCount)
   382  	dst = BytesOrder.AppendUint32(dst, msg.ThisPacketID)
   383  	return dst
   384  }
   385  
   386  // ToBytesCrypt returns a slice of bytes representing msg's internal structures before encryption.
   387  func (msg *MessageCrypt) ToBytesCrypt() []byte {
   388  	dst := make([]byte, 0, OpcodeKeyIDBytesTotal+PacketIDBytesTotal)
   389  	dst = append(dst, msg.PrevPacketIDsCount)
   390  	dst = BytesOrder.AppendUint32(dst, msg.ThisPacketID)
   391  	return dst
   392  }
   393  
   394  // MessageCrypt2 is a P_CONTROL_HARD_RESET_CLIENT_V3-type OpenVPN message with authentication and encryption
   395  // using a wrapped client key which is authenticated and encrypted with a server key.
   396  type MessageCrypt2 struct {
   397  	MessageCrypt
   398  	WrappedKey
   399  }
   400  
   401  // DecryptAndAuthenticate decrypts and authenticates msg's encrypted bytes (WrappedKey before MessageCrypt).
   402  func (msg *MessageCrypt2) DecryptAndAuthenticate(ad *AuthDigest, sk *StaticKey) bool {
   403  	if !msg.WrappedKey.DecryptAndAuthenticate(ad, sk) {
   404  		return false
   405  	}
   406  	return msg.MessageCrypt.DecryptAndAuthenticate(ad, &msg.WrappedKey.StaticKey)
   407  }
   408  
   409  // EncryptAndSign encrypts and signs msg's plain bytes (WrappedKey before MessageCrypt).
   410  func (msg *MessageCrypt2) EncryptAndSign(ad *AuthDigest, sk *StaticKey) error {
   411  	if err := msg.WrappedKey.EncryptAndSign(ad, sk); err != nil {
   412  		return err
   413  	}
   414  	return msg.MessageCrypt.EncryptAndSign(ad, &msg.WrappedKey.StaticKey)
   415  }
   416  
   417  // FromBytes fills msg's internal structures from a slice of bytes.
   418  func (msg *MessageCrypt2) FromBytes(src []byte) error {
   419  	// Any MessageCrypt2 is between 344 and 600 bytes (with a header).
   420  	if len(src) < MessageCrypt2BytesMin || len(src) > MessageCrypt2BytesMax {
   421  		return ErrInvalidSourceLength
   422  	}
   423  
   424  	// Parse MessageHeader
   425  	hdr := &MessageHeader{}
   426  	if err := hdr.FromBytes(src[:OpcodeKeyIDBytesTotal]); err != nil {
   427  		return err
   428  	}
   429  
   430  	// Match MessageHeader.Opcode
   431  	if hdr.Opcode != OpcodeControlHardResetClientV3 {
   432  		return ErrInvalidHeaderOpcode
   433  	}
   434  
   435  	// Parse everything else
   436  	return msg.FromBytesHeadless(src[OpcodeKeyIDBytesTotal:], hdr)
   437  }
   438  
   439  // FromBytesHeadless fills msg's internal structures from a slice of bytes and uses a pre-filled header.
   440  func (msg *MessageCrypt2) FromBytesHeadless(src []byte, hdr *MessageHeader) error {
   441  	// Any MessageCrypt2 is between 343 and 1077 bytes long (without a header).
   442  	if len(src) < MessageCrypt2BytesMinHL || len(src) > MessageCrypt2BytesMaxHL {
   443  		return ErrInvalidSourceLength
   444  	}
   445  
   446  	if err := msg.MessageCrypt.FromBytesHeadless(src[:MessageCryptBytesTotalHL], hdr); err != nil {
   447  		return err
   448  	}
   449  
   450  	return msg.WrappedKey.FromBytes(src[MessageCryptBytesTotalHL:])
   451  }
   452  
   453  // Match returns true if msg's internal structures have valid values.
   454  func (msg *MessageCrypt2) Match(ignoreTimestamp, ignoreCrypto bool, ad *AuthDigest, sk *StaticKey, cks []*WrappedKey) bool {
   455  	if !(msg.LocalSessionID > 0 && (msg.ReplayPacketID == 1 || msg.ReplayPacketID == 0x0f000001) &&
   456  		(ignoreTimestamp || msg.ValidateReplayTimestamp(time.Now()))) {
   457  		return false
   458  	}
   459  
   460  	if ignoreCrypto {
   461  		return true
   462  	}
   463  
   464  	if len(cks) > 0 {
   465  		for _, ck := range cks {
   466  			if bytes.Equal(ck.HMAC, msg.WrappedKey.HMAC) && bytes.Equal(ck.Encrypted, msg.WrappedKey.Encrypted) {
   467  				return msg.MessageCrypt.DecryptAndAuthenticate(ad, &ck.StaticKey) &&
   468  					msg.PrevPacketIDsCount == 0 && msg.ThisPacketID == 0
   469  			}
   470  		}
   471  		return false
   472  	}
   473  
   474  	return sk == nil || (msg.DecryptAndAuthenticate(ad, sk) && msg.PrevPacketIDsCount == 0 && msg.ThisPacketID == 0)
   475  }
   476  
   477  // ToBytes returns a slice of bytes representing msg's internal structures.
   478  func (msg *MessageCrypt2) ToBytes() []byte {
   479  	return slices.Concat(msg.MessageCrypt.ToBytes(), msg.WrappedKey.ToBytes())
   480  }
   481  
   482  // MessageTraitAuth contains fields and implements features related to authentication.
   483  type MessageTraitAuth struct {
   484  	// Digest is a pointer to AuthDigest to be used for authentication.
   485  	Digest *AuthDigest
   486  	// HMAC is a hash-based messaged authentication code used to verify message integrity.
   487  	HMAC []byte
   488  }
   489  
   490  // AuthenticateOnClient returns true if msg composed on the client has a valid HMAC.
   491  func (msg *MessageTraitAuth) AuthenticateOnClient(ad *AuthDigest, sk *StaticKey, xp func() []byte) bool {
   492  	// No supported digest returns an HMAC of 0 bytes.
   493  	if len(msg.HMAC) == 0 {
   494  		return false
   495  	}
   496  
   497  	// Check that there is a valid StaticKey.
   498  	// A half key may be provided as a server key to validate a WrappedKey.
   499  	if sk == nil || !(len(sk.KeyBytes) == StaticKeyBytesTotal || len(sk.KeyBytes) == StaticKeyBytesHalf) {
   500  		return false
   501  	}
   502  
   503  	// Obtain a slice of bytes to compute a digest of.
   504  	plain := xp()
   505  
   506  	// Firstly, try the given digest.
   507  	if ad != nil {
   508  		if len(msg.HMAC) == ad.Size && ad.HMACValidateOnClient(sk, plain, msg.HMAC) {
   509  			msg.Digest = ad
   510  			return true
   511  		}
   512  		return false
   513  	}
   514  
   515  	// Secondly, try the last successful one saved as Digest.
   516  	if msg.Digest != nil && len(msg.HMAC) == msg.Digest.Size && msg.Digest.HMACValidateOnClient(sk, plain, msg.HMAC) {
   517  		return true
   518  	}
   519  
   520  	// Finally, try all other supported digests one by one.
   521  	for _, mad := range AuthDigests {
   522  		if mad != msg.Digest && len(msg.HMAC) == mad.Size && mad.HMACValidateOnClient(sk, plain, msg.HMAC) {
   523  			msg.Digest = mad
   524  			return true
   525  		}
   526  	}
   527  
   528  	return false
   529  }
   530  
   531  // AuthenticateOnServer returns true if msg composed on the server has a valid HMAC.
   532  func (msg *MessageTraitAuth) AuthenticateOnServer(ad *AuthDigest, sk *StaticKey, xp func() []byte) bool {
   533  	// No supported digest returns an HMAC of 0 bytes.
   534  	if len(msg.HMAC) == 0 {
   535  		return false
   536  	}
   537  
   538  	// Check that there is a valid StaticKey.
   539  	if sk == nil || len(sk.KeyBytes) != StaticKeyBytesTotal {
   540  		return false
   541  	}
   542  
   543  	// Obtain a slice of bytes to compute a digest of.
   544  	plain := xp()
   545  
   546  	// Firstly, try the given digest.
   547  	if ad != nil {
   548  		if len(msg.HMAC) == ad.Size && ad.HMACValidateOnServer(sk, plain, msg.HMAC) {
   549  			msg.Digest = ad
   550  			return true
   551  		}
   552  		return false
   553  	}
   554  
   555  	// Secondly, try the last successful one saved as Digest.
   556  	if msg.Digest != nil && len(msg.HMAC) == msg.Digest.Size && msg.Digest.HMACValidateOnServer(sk, plain, msg.HMAC) {
   557  		return true
   558  	}
   559  
   560  	// Finally, try all other supported digests one by one.
   561  	for _, mad := range AuthDigests {
   562  		if mad != msg.Digest && len(msg.HMAC) == mad.Size && mad.HMACValidateOnServer(sk, plain, msg.HMAC) {
   563  			msg.Digest = mad
   564  			return true
   565  		}
   566  	}
   567  
   568  	return false
   569  }
   570  
   571  // SignOnClient computes an HMAC for msg composed on the client.
   572  func (msg *MessageTraitAuth) SignOnClient(ad *AuthDigest, sk *StaticKey, xp func() []byte) error {
   573  	// Check that there is a valid StaticKey.
   574  	// A half key may be provided as a server key to sign a WrappedKey.
   575  	if sk == nil || !(len(sk.KeyBytes) == StaticKeyBytesTotal || len(sk.KeyBytes) == StaticKeyBytesHalf) {
   576  		return ErrInvalidAuthPrerequisites
   577  	}
   578  
   579  	// Obtain a slice of bytes to compute a digest of.
   580  	plain := xp()
   581  
   582  	// Firstly, try the given digest.
   583  	if ad != nil {
   584  		msg.HMAC = ad.HMACGenerateOnClient(sk, plain)
   585  	}
   586  
   587  	// Secondly, try the internal Digest.
   588  	if msg.Digest != nil {
   589  		msg.HMAC = msg.Digest.HMACGenerateOnClient(sk, plain)
   590  	}
   591  
   592  	// Finally, use the default digest.
   593  	msg.Digest, msg.HMAC = AuthDigestDefault, AuthDigestDefault.HMACGenerateOnClient(sk, plain)
   594  
   595  	return nil
   596  }
   597  
   598  // SignOnServer computes an HMAC for msg composed on the server.
   599  func (msg *MessageTraitAuth) SignOnServer(ad *AuthDigest, sk *StaticKey, xp func() []byte) error {
   600  	// Check that there is a valid StaticKey.
   601  	// A half key may be provided as a server key to sign a WrappedKey.
   602  	if sk == nil || !(len(sk.KeyBytes) == StaticKeyBytesTotal || len(sk.KeyBytes) == StaticKeyBytesHalf) {
   603  		return ErrInvalidAuthPrerequisites
   604  	}
   605  
   606  	// Obtain a slice of bytes to compute a digest of.
   607  	plain := xp()
   608  
   609  	// Firstly, try the given digest.
   610  	if ad != nil {
   611  		msg.HMAC = ad.HMACGenerateOnServer(sk, plain)
   612  	}
   613  
   614  	// Secondly, try the internal Digest.
   615  	if msg.Digest != nil {
   616  		msg.HMAC = msg.Digest.HMACGenerateOnServer(sk, plain)
   617  	}
   618  
   619  	// Finally, use the default digest.
   620  	msg.Digest, msg.HMAC = AuthDigestDefault, AuthDigestDefault.HMACGenerateOnServer(sk, plain)
   621  
   622  	return nil
   623  }
   624  
   625  // MessageTraitCrypt contains fields and implements features related to en-/decryption.
   626  type MessageTraitCrypt struct {
   627  	// Cipher is a pointer to CryptCipher to be used for encryption.
   628  	Cipher *CryptCipher
   629  	// Encrypted contains a number of bytes to be decrypted.
   630  	Encrypted []byte
   631  }
   632  
   633  // DecryptOnClient decrypts msg's encrypted bytes with an encryption key used by the server.
   634  func (msg *MessageTraitCrypt) DecryptOnClient(sk *StaticKey, ta *MessageTraitAuth, xd func([]byte) error) error {
   635  	if sk == nil || msg.Cipher == nil || ta.Digest == nil || len(ta.HMAC) != ta.Digest.Size {
   636  		return ErrInvalidCryptPrerequisites
   637  	}
   638  
   639  	plain := msg.Cipher.DecryptOnClient(sk, ta.HMAC[:min(msg.Cipher.SizeBlock, ta.Digest.Size)], msg.Encrypted)
   640  
   641  	return xd(plain)
   642  }
   643  
   644  // DecryptOnServer decrypts msg's encrypted bytes with an encryption key used by the client.
   645  func (msg *MessageTraitCrypt) DecryptOnServer(sk *StaticKey, ta *MessageTraitAuth, xd func([]byte) error) error {
   646  	if sk == nil || msg.Cipher == nil || ta.Digest == nil || len(ta.HMAC) != ta.Digest.Size {
   647  		return ErrInvalidCryptPrerequisites
   648  	}
   649  
   650  	plain := msg.Cipher.DecryptOnServer(sk, ta.HMAC[:min(msg.Cipher.SizeBlock, ta.Digest.Size)], msg.Encrypted)
   651  
   652  	return xd(plain)
   653  }
   654  
   655  // EncryptOnClient encrypts msg's plain bytes with a decryption key used by the server.
   656  func (msg *MessageTraitCrypt) EncryptOnClient(sk *StaticKey, ta *MessageTraitAuth, xe func() []byte) error {
   657  	if sk == nil || msg.Cipher == nil || ta.Digest == nil || len(ta.HMAC) != ta.Digest.Size {
   658  		return ErrInvalidCryptPrerequisites
   659  	}
   660  
   661  	plain := xe()
   662  
   663  	msg.Encrypted = msg.Cipher.EncryptOnClient(sk, ta.HMAC[:min(msg.Cipher.SizeBlock, ta.Digest.Size)], plain)
   664  	if len(plain) != len(msg.Encrypted) {
   665  		return ErrInvalidEncryptedLength
   666  	}
   667  
   668  	return nil
   669  }
   670  
   671  // EncryptOnServer encrypts msg's plain bytes with a decryption key used by the client.
   672  func (msg *MessageTraitCrypt) EncryptOnServer(sk *StaticKey, ta *MessageTraitAuth, xe func() []byte) error {
   673  	if sk == nil || msg.Cipher == nil || ta.Digest == nil || len(ta.HMAC) != ta.Digest.Size {
   674  		return ErrInvalidCryptPrerequisites
   675  	}
   676  
   677  	plain := xe()
   678  
   679  	msg.Encrypted = msg.Cipher.EncryptOnServer(sk, ta.HMAC[:min(msg.Cipher.SizeBlock, ta.Digest.Size)], plain)
   680  	if len(plain) != len(msg.Encrypted) {
   681  		return ErrInvalidEncryptedLength
   682  	}
   683  
   684  	return nil
   685  }
   686  
   687  // MessageTraitReplay contains fields and implements features related to replay protection.
   688  type MessageTraitReplay struct {
   689  	// ReplayPacketID is a 4-byte packet ID used for replay protection.
   690  	ReplayPacketID uint32
   691  	// ReplayTimestamp is a 4-byte timestamp used for replay protection.
   692  	ReplayTimestamp uint32
   693  }
   694  
   695  // ValidateReplayTimestamp returns true if msg has a valid ReplayTimestamp (relative to the provided time).
   696  func (msg *MessageTraitReplay) ValidateReplayTimestamp(t time.Time) bool {
   697  	tReplay := time.Unix(int64(msg.ReplayTimestamp), 0)
   698  	tNowLow := t.UTC().Add(-TimestampValidationInterval)
   699  	tNowHigh := t.UTC().Add(TimestampValidationInterval)
   700  	return tReplay.After(tNowLow) && tReplay.Before(tNowHigh)
   701  }
   702  
   703  // MetaData is an optional set of Type and Payload that may be included into WrappedKey.
   704  type MetaData struct {
   705  	// Payload contains a number of bytes of variable length corresponding to Type.
   706  	Payload []byte
   707  	// Type indicates how to parse Payload correctly. It may equal 0x00 for any user defined data
   708  	// and 0x01 for a 4-byte timestamp which enables discarding old client keys on the server.
   709  	Type uint8
   710  }
   711  
   712  // WrappedKey is an authenticated and encrypted client key used to encrypt MessageCrypt in the crypt2 mode.
   713  type WrappedKey struct {
   714  	MetaData
   715  	StaticKey
   716  	MessageTraitAuth
   717  	MessageTraitCrypt
   718  }
   719  
   720  // Authenticate returns true if wk's HMAC is valid.
   721  func (wk *WrappedKey) Authenticate(ad *AuthDigest, sk *StaticKey) bool {
   722  	return wk.MessageTraitAuth.AuthenticateOnClient(ad, sk, wk.ToBytesAuth)
   723  }
   724  
   725  // DecryptAndAuthenticate decrypts wk's encrypted bytes before calling Authenticate.
   726  func (wk *WrappedKey) DecryptAndAuthenticate(ad *AuthDigest, sk *StaticKey) bool {
   727  	if len(wk.Encrypted) < StaticKeyBytesTotal ||
   728  		len(wk.Encrypted) > WrappedKeyBytesMax-LengthBytesTotal-CryptHMACBytesTotal ||
   729  		wk.MessageTraitCrypt.DecryptOnClient(sk, &wk.MessageTraitAuth, wk.FromBytesCrypt) != nil {
   730  		return false
   731  	}
   732  	return wk.Authenticate(ad, sk)
   733  }
   734  
   735  // EncryptAndSign encrypts wk's plain bytes before calling Sign.
   736  func (wk *WrappedKey) EncryptAndSign(ad *AuthDigest, sk *StaticKey) error {
   737  	if err := wk.MessageTraitCrypt.EncryptOnServer(sk, &wk.MessageTraitAuth, wk.ToBytesCrypt); err != nil {
   738  		return err
   739  	}
   740  	return wk.Sign(ad, sk)
   741  }
   742  
   743  // FromBase64 fills wk's internal structures (including decrypted StaticKey bytes) from a base64 string.
   744  func (wk *WrappedKey) FromBase64(s string) error {
   745  	src, err := base64.StdEncoding.DecodeString(s)
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	if len(src) < WrappedKeyBytesMin+StaticKeyBytesTotal || len(src) > WrappedKeyBytesMax+StaticKeyBytesTotal {
   751  		return ErrInvalidSourceLength
   752  	}
   753  
   754  	wk.StaticKey.KeyBytes = src[:StaticKeyBytesTotal]
   755  
   756  	return wk.FromBytes(src[StaticKeyBytesTotal:])
   757  }
   758  
   759  // FromBytes fills wk's internal structures from a slice of bytes.
   760  func (wk *WrappedKey) FromBytes(src []byte) error {
   761  	// Any WrappedKey has a 2-byte length at the end. Ensure that it has a valid value.
   762  	if len(src) < WrappedKeyBytesMin || len(src) > WrappedKeyBytesMax ||
   763  		len(src) != int(BytesOrder.Uint16(src[len(src)-LengthBytesTotal:])) {
   764  		return ErrInvalidSourceLength
   765  	}
   766  
   767  	// Any WrappedKey has a 32-byte SHA-256 HMAC at the beginning.
   768  	wk.Digest, wk.HMAC = AuthDigestDefault, src[:CryptHMACBytesTotal]
   769  
   770  	// Any WrappedKey has an Encrypted part of at least 256 bytes between HMAC and Length.
   771  	wk.Cipher, wk.Encrypted = CryptCipherDefault, src[CryptHMACBytesTotal:len(src)-LengthBytesTotal]
   772  
   773  	return nil
   774  }
   775  
   776  // FromBytesCrypt fills wk's internal structures from a slice of bytes after decryption.
   777  func (wk *WrappedKey) FromBytesCrypt(plain []byte) error {
   778  	if len(plain) != len(wk.Encrypted) {
   779  		return ErrInvalidPlainLength
   780  	}
   781  
   782  	// Any WrappedKey has a StaticKey at the beginning of the plain text.
   783  	wk.StaticKey.KeyBytes = plain[:StaticKeyBytesTotal]
   784  
   785  	// Any WrappedKey may have a MetaData.Type between StaticKey and MetaData in the plain text.
   786  	if len(plain) > StaticKeyBytesTotal {
   787  		wk.MetaData.Type = plain[StaticKeyBytesTotal]
   788  	}
   789  
   790  	// Any KeyMata may have MetaData.Payload at the end of the plain text.
   791  	if len(plain) > StaticKeyBytesTotal+MetaDataTypeBytesTotal {
   792  		wk.MetaData.Payload = plain[StaticKeyBytesTotal+MetaDataTypeBytesTotal:]
   793  	}
   794  
   795  	return nil
   796  }
   797  
   798  // FromClientKeyFile fills wk's internal structures (including decrypted StaticKey bytes) from a given file.
   799  func (wk *WrappedKey) FromClientKeyFile(path string) error {
   800  	err := wk.StaticKey.FromFile(path, StaticKeyFromFileBase64, 0, wk.StaticKey.FromBase64)
   801  	if err != nil {
   802  		return err
   803  	}
   804  
   805  	if len(wk.StaticKey.KeyBytes) < WrappedKeyBytesMin || len(wk.StaticKey.KeyBytes) > WrappedKeyBytesMax {
   806  		return ErrInvalidStaticKeyFileContents
   807  	}
   808  
   809  	err = wk.FromBytes(wk.StaticKey.KeyBytes[StaticKeyBytesTotal:])
   810  	if err != nil {
   811  		return err
   812  	}
   813  
   814  	wk.StaticKey.KeyBytes = wk.StaticKey.KeyBytes[:StaticKeyBytesTotal]
   815  	return nil
   816  }
   817  
   818  // Sign computes and fills wk's HMAC.
   819  func (wk *WrappedKey) Sign(ad *AuthDigest, sk *StaticKey) error {
   820  	return wk.MessageTraitAuth.SignOnClient(ad, sk, wk.ToBytesAuth)
   821  }
   822  
   823  // ToBytes returns a slice of bytes representing wk's internal structures.
   824  func (wk *WrappedKey) ToBytes() []byte {
   825  	dst := make([]byte, 0, len(wk.HMAC)+len(wk.Encrypted)+LengthBytesTotal)
   826  	dst = append(dst, wk.HMAC...)
   827  	dst = append(dst, wk.Encrypted...)
   828  	dst = BytesOrder.AppendUint16(dst, uint16(cap(dst)))
   829  	return dst
   830  }
   831  
   832  // ToBytesAuth returns a slice of bytes representing wk's internal structures without HMAC.
   833  func (wk *WrappedKey) ToBytesAuth() []byte {
   834  	if len(wk.MetaData.Payload) > 0 {
   835  		dst := make([]byte, 0, LengthBytesTotal+len(wk.StaticKey.KeyBytes)+MetaDataTypeBytesTotal+len(wk.MetaData.Payload))
   836  		dst = BytesOrder.AppendUint16(dst, uint16(cap(dst)+CryptHMACBytesTotal))
   837  		dst = append(dst, wk.StaticKey.KeyBytes...)
   838  		dst = append(dst, wk.MetaData.Type)
   839  		dst = append(dst, wk.MetaData.Payload...)
   840  		return dst
   841  	} else {
   842  		dst := make([]byte, 0, LengthBytesTotal+len(wk.StaticKey.KeyBytes))
   843  		dst = BytesOrder.AppendUint16(dst, uint16(cap(dst)+CryptHMACBytesTotal))
   844  		dst = append(dst, wk.StaticKey.KeyBytes...)
   845  		return dst
   846  	}
   847  }
   848  
   849  // ToBytesCrypt returns a slice of bytes representing wk's internal structures before encryption.
   850  func (wk *WrappedKey) ToBytesCrypt() []byte {
   851  	if len(wk.MetaData.Payload) > 0 {
   852  		dst := make([]byte, 0, len(wk.StaticKey.KeyBytes)+MetaDataTypeBytesTotal+len(wk.MetaData.Payload))
   853  		dst = append(dst, wk.StaticKey.KeyBytes...)
   854  		dst = append(dst, wk.MetaData.Type)
   855  		dst = append(dst, wk.MetaData.Payload...)
   856  		return dst
   857  	} else {
   858  		return wk.StaticKey.KeyBytes
   859  	}
   860  }
   861  
   862  var (
   863  	BytesOrder = binary.BigEndian
   864  
   865  	ErrInvalidAuthPrerequisites  = errors.New("invalid auth prerequisites")
   866  	ErrInvalidCryptPrerequisites = errors.New("invalid crypt prerequisites")
   867  	ErrInvalidEncryptedLength    = errors.New("invalid encrypted length")
   868  	ErrInvalidHeaderOpcode       = errors.New("invalid header opcode")
   869  	ErrInvalidHMACLength         = errors.New("invalid HMAC length")
   870  	ErrInvalidPlainLength        = errors.New("invalid plain length")
   871  	ErrInvalidSourceLength       = errors.New("invalid source length")
   872  	ErrMissingReusableHeader     = errors.New("missing reusable header")
   873  )
   874  
   875  const (
   876  	/*
   877  	 *	Irrelevant MessageHeader.Opcode values:
   878  	 *
   879  	 *	OpcodeControlHardResetClientV1  uint8 = 1
   880  	 *	OpcodeControlHardResetServerV1  uint8 = 2
   881  	 *	OpcodeControlSoftResetV1        uint8 = 3
   882  	 *	OpcodeControlV1                 uint8 = 4
   883  	 *	OpcodeAckV1                     uint8 = 5
   884  	 *	OpcodeDataV1                    uint8 = 6
   885  	 *	OpcodeControlHardResetServerV2  uint8 = 8
   886  	 *	OpcodeDataV2                    uint8 = 9
   887  	 *	OpcodeControlWrappedClientKeyV1 uint8 = 11
   888  	 */
   889  
   890  	OpcodeControlHardResetClientV2 uint8 = 7
   891  	OpcodeControlHardResetClientV3 uint8 = 10
   892  
   893  	KeyIDMask uint8 = 0b1<<OpcodeShift - 1
   894  
   895  	OpcodeShift = 3
   896  
   897  	AckPacketIDsCountBytesTotal = 1
   898  	LengthBytesTotal            = 2
   899  	MetaDataPayloadBytesMax     = WrappedKeyBytesMax - MetaDataTypeBytesTotal - WrappedKeyBytesMin
   900  	MetaDataTypeBytesTotal      = 1
   901  	OpcodeKeyIDBytesTotal       = 1
   902  	PacketIDBytesTotal          = 4
   903  	SessionIDBytesTotal         = 8
   904  	TimestampBytesTotal         = 4
   905  
   906  	WrappedKeyBytesMax = 1024
   907  	WrappedKeyBytesMin = CryptHMACBytesTotal + StaticKeyBytesTotal + LengthBytesTotal
   908  
   909  	TimestampValidationInterval = 15 * time.Second
   910  
   911  	MessagePlainBytesTotalHL = SessionIDBytesTotal + AckPacketIDsCountBytesTotal + PacketIDBytesTotal
   912  	MessagePlainBytesTotal   = OpcodeKeyIDBytesTotal + MessagePlainBytesTotalHL
   913  	MessageAuthBytesMaxHL    = MessagePlainBytesTotalHL + AuthHMACBytesMax + PacketIDBytesTotal + TimestampBytesTotal
   914  	MessageAuthBytesMax      = OpcodeKeyIDBytesTotal + MessageAuthBytesMaxHL
   915  	MessageAuthBytesMinHL    = MessagePlainBytesTotalHL + AuthHMACBytesMin + PacketIDBytesTotal + TimestampBytesTotal
   916  	MessageAuthBytesMin      = OpcodeKeyIDBytesTotal + MessageAuthBytesMinHL
   917  	MessageCryptBytesTotalHL = MessagePlainBytesTotalHL + PacketIDBytesTotal + TimestampBytesTotal + CryptHMACBytesTotal
   918  	MessageCryptBytesTotal   = OpcodeKeyIDBytesTotal + MessageCryptBytesTotalHL
   919  	MessageCrypt2BytesMinHL  = MessageCryptBytesTotalHL + LengthBytesTotal + CryptHMACBytesTotal + StaticKeyBytesTotal
   920  	MessageCrypt2BytesMin    = OpcodeKeyIDBytesTotal + MessageCrypt2BytesMinHL
   921  	MessageCrypt2BytesMaxHL  = MessageCrypt2BytesMinHL + MetaDataTypeBytesTotal + MetaDataPayloadBytesMax
   922  	MessageCrypt2BytesMax    = OpcodeKeyIDBytesTotal + MessageCrypt2BytesMaxHL
   923  )
   924  
   925  // WrappedKeyNewFromBase64 returns a pointer to WrappedKey filled with bytes from a given base64 string.
   926  func WrappedKeyNewFromBase64(s string) *WrappedKey {
   927  	wk := &WrappedKey{}
   928  	_ = wk.FromBase64(s)
   929  	return wk
   930  }
   931  
   932  // References:
   933  //
   934  //	- Official manuals:
   935  //		https://openvpn.net/community-resources/openvpn-cryptographic-layer/
   936  //		https://openvpn.net/community-resources/openvpn-protocol/
   937  //		https://openvpn.net/community-resources/reference-manual-for-openvpn-2-6/
   938  //		https://openvpn.net/faq/changed-hex-bytes-in-the-static-key-the-key-still-connects-to-a-remote-peer-using-the-original-key/
   939  //
   940  //	- OpenVPN codebase:
   941  //		https://github.com/OpenVPN/openvpn/
   942  //		https://github.com/OpenVPN/openvpn3/
   943  //
   944  //	- Third-party solutions:
   945  //		https://github.com/corelight/zeek-openvpn/blob/master/src/openvpn-analyzer.pac
   946  //		https://github.com/ntop/nDPI/blob/dev/src/lib/protocols/openvpn.c
   947  //		https://github.com/yrutschle/sslh/blob/master/probe.c
   948  //		https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-openvpn.c