From 1a5195b5231ea4ccfa61db68270170de75cef1af Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 29 Feb 2020 21:05:06 +0000 Subject: [PATCH] fix comments * fix comments * update to test with 1.14 --- .github/workflows/testing.yml | 2 +- .github/workflows/testingv8.yml | 2 +- README.md | 2 +- client/ASExchange.go | 10 +--- client/network.go | 13 +---- credentials/ccache.go | 17 +------ crypto/aes128-cts-hmac-sha1-96.go | 44 ---------------- crypto/aes128-cts-hmac-sha256-128.go | 7 +-- crypto/aes256-cts-hmac-sha1-96.go | 44 ---------------- crypto/aes256-cts-hmac-sha384-192.go | 7 +-- crypto/common/common.go | 19 ++----- crypto/des3-cbc-sha1-kd.go | 35 ------------- crypto/etype/etype.go | 24 ++++----- crypto/rc4-hmac.go | 4 +- crypto/rfc3961/encryption.go | 6 --- crypto/rfc3961/keyDerivation.go | 13 +---- crypto/rfc3961/nfold.go | 23 +-------- crypto/rfc3962/keyDerivation.go | 13 ++--- crypto/rfc4757/keyDerivation.go | 15 ------ crypto/rfc8009/encryption.go | 7 +-- crypto/rfc8009/keyDerivation.go | 10 ---- gssapi/MICToken.go | 30 +---------- gssapi/wrapToken.go | 46 +---------------- keytab/keytab.go | 13 ++--- messages/APRep.go | 15 ------ messages/APReq.go | 30 +---------- messages/KDCRep.go | 8 +-- messages/KRBSafe.go | 18 ------- pac/credentials_info.go | 4 -- pac/kerb_validation_info.go | 5 -- pac/signature_data.go | 12 ----- pac/supplemental_cred.go | 3 -- service/cache.go | 22 +------- spnego/krb5Token.go | 23 --------- spnego/negotiationToken.go | 34 +------------ types/Authenticator.go | 23 +-------- types/AuthorizationData.go | 68 ------------------------- types/HostAddress.go | 24 --------- types/KerberosFlags.go | 56 -------------------- v8/README.md | 2 +- v8/client/ASExchange.go | 10 +--- v8/client/network.go | 13 +---- v8/credentials/ccache.go | 17 +------ v8/crypto/aes128-cts-hmac-sha1-96.go | 44 ---------------- v8/crypto/aes128-cts-hmac-sha256-128.go | 7 +-- v8/crypto/aes256-cts-hmac-sha1-96.go | 44 ---------------- v8/crypto/aes256-cts-hmac-sha384-192.go | 7 +-- v8/crypto/common/common.go | 19 ++----- v8/crypto/des3-cbc-sha1-kd.go | 35 ------------- v8/crypto/etype/etype.go | 24 ++++----- v8/crypto/rc4-hmac.go | 4 +- v8/crypto/rfc3961/encryption.go | 6 --- v8/crypto/rfc3961/keyDerivation.go | 11 +--- v8/crypto/rfc3961/nfold.go | 23 +-------- v8/crypto/rfc3962/keyDerivation.go | 13 ++--- v8/crypto/rfc4757/keyDerivation.go | 15 ------ v8/crypto/rfc8009/encryption.go | 7 +-- v8/crypto/rfc8009/keyDerivation.go | 10 ---- v8/gssapi/MICToken.go | 30 +---------- v8/gssapi/wrapToken.go | 46 +---------------- v8/keytab/keytab.go | 13 ++--- v8/messages/APRep.go | 15 ------ v8/messages/APReq.go | 29 +---------- v8/messages/KDCRep.go | 8 +-- v8/messages/KRBSafe.go | 18 ------- v8/pac/credentials_info.go | 4 -- v8/pac/kerb_validation_info.go | 5 -- v8/pac/signature_data.go | 12 ----- v8/pac/supplemental_cred.go | 3 -- v8/service/cache.go | 22 +------- v8/spnego/krb5Token.go | 23 --------- v8/spnego/negotiationToken.go | 34 +------------ v8/types/Authenticator.go | 23 +-------- v8/types/AuthorizationData.go | 68 ------------------------- v8/types/HostAddress.go | 24 --------- v8/types/KerberosFlags.go | 56 -------------------- 76 files changed, 95 insertions(+), 1400 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 7bd91d5b..b877309b 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.11.x', '1.12.x', '1.13.x' ] + go: [ '1.12.x', '1.13.x', '1.14.x' ] env: TEST_KDC_ADDR: 127.0.0.1 TEST_HTTP_URL: http://cname.test.gokrb5 diff --git a/.github/workflows/testingv8.yml b/.github/workflows/testingv8.yml index 2fb35fa5..a83c46cd 100644 --- a/.github/workflows/testingv8.yml +++ b/.github/workflows/testingv8.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.11.x', '1.12.x', '1.13.x' ] + go: [ '1.12.x', '1.13.x', '1.14.x' ] env: TEST_KDC_ADDR: 127.0.0.1 TEST_HTTP_URL: http://cname.test.gokrb5 diff --git a/README.md b/README.md index 5fb8fa9c..48b4d54a 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Development will be focused on the latest major version. New features will only #### Go Version Support +![Go version](https://img.shields.io/badge/Go-1.14-brightgreen.svg) ![Go version](https://img.shields.io/badge/Go-1.13-brightgreen.svg) ![Go version](https://img.shields.io/badge/Go-1.12-brightgreen.svg) -![Go version](https://img.shields.io/badge/Go-1.11-brightgreen.svg) gokrb5 may work with other versions of Go but they are not tested. diff --git a/client/ASExchange.go b/client/ASExchange.go index 9d1a2f3f..dfda2e3a 100644 --- a/client/ASExchange.go +++ b/client/ASExchange.go @@ -145,15 +145,7 @@ func setPAData(cl *Client, krberr *messages.KRBError, ASReq *messages.ASReq) err // preAuthEType establishes what encryption type to use for pre-authentication from the KRBError returned from the KDC. func preAuthEType(krberr *messages.KRBError) (etype etype.EType, err error) { - //The preferred ordering of the "hint" pre-authentication data that - //affect client key selection is: ETYPE-INFO2, followed by ETYPE-INFO, - //followed by PW-SALT. - //A KDC SHOULD NOT send PA-PW-SALT when issuing a KRB-ERROR message - //that requests additional pre-authentication. Implementation note: - //Some KDC implementations issue an erroneous PA-PW-SALT when issuing a - //KRB-ERROR message that requests additional pre-authentication. - //Therefore, clients SHOULD ignore a PA-PW-SALT accompanying a - //KRB-ERROR message that requests additional pre-authentication. + //RFC 4120 5.2.7.5 covers the preference order of ETYPE-INFO2 and ETYPE-INFO. var etypeID int32 var pas types.PADataSequence e := pas.Unmarshal(krberr.EData) diff --git a/client/network.go b/client/network.go index 493fb2f3..3cc1b19a 100644 --- a/client/network.go +++ b/client/network.go @@ -172,18 +172,7 @@ func (cl *Client) sendUDP(conn *net.UDPConn, b []byte) ([]byte, error) { func (cl *Client) sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) { defer conn.Close() var r []byte - /* - RFC https://tools.ietf.org/html/rfc4120#section-7.2.2 - Each request (KRB_KDC_REQ) and response (KRB_KDC_REP or KRB_ERROR) - sent over the TCP stream is preceded by the length of the request as - 4 octets in network byte order. The high bit of the length is - reserved for future expansion and MUST currently be set to zero. If - a KDC that does not understand how to interpret a set high bit of the - length encoding receives a request with the high order bit of the - length set, it MUST return a KRB-ERROR message with the error - KRB_ERR_FIELD_TOOLONG and MUST close the TCP stream. - NB: network byte order == big endian - */ + // RFC 4120 7.2.2 specifies the first 4 bytes indicate the length of the message in big endian order. var buf bytes.Buffer err := binary.Write(&buf, binary.BigEndian, uint32(len(b))) if err != nil { diff --git a/credentials/ccache.go b/credentials/ccache.go index 98ec29b9..7a85f46f 100644 --- a/credentials/ccache.go +++ b/credentials/ccache.go @@ -17,15 +17,6 @@ const ( headerFieldTagKDCOffset = 1 ) -// The first byte of the file always has the value 5. -// The value of the second byte contains the version number (1 through 4) -// Versions 1 and 2 of the file format use native byte order for integer representations. -// Versions 3 and 4 always use big-endian byte order -// After the two-byte version indicator, the file has three parts: -// 1) the header (in version 4 only) -// 2) the default principal name -// 3) a sequence of credentials - // CCache is the file credentials cache as define here: https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html type CCache struct { Version uint8 @@ -257,13 +248,7 @@ func (c *CCache) GetEntries() []*Credential { } func (h *headerField) valid() bool { - // At this time there is only one defined header field. - // Its tag value is 1, its length is always 8. - // Its contents are two 32-bit integers giving the seconds and microseconds - // of the time offset of the KDC relative to the client. - // Adding this offset to the current time on the client should give the current time on the KDC, if that offset has not changed since the initial authentication. - - // Done as a switch in case other tag values are added in the future. + // See https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html - Header format switch h.tag { case headerFieldTagKDCOffset: if h.length != 8 || len(h.value) != 8 { diff --git a/crypto/aes128-cts-hmac-sha1-96.go b/crypto/aes128-cts-hmac-sha1-96.go index 90b5df08..ee04823f 100644 --- a/crypto/aes128-cts-hmac-sha1-96.go +++ b/crypto/aes128-cts-hmac-sha1-96.go @@ -14,50 +14,6 @@ import ( ) // RFC 3962 -//+--------------------------------------------------------------------+ -//| protocol key format 128- or 256-bit string | -//| | -//| string-to-key function PBKDF2+DK with variable | -//| iteration count (see | -//| above) | -//| | -//| default string-to-key parameters 00 00 10 00 | -//| | -//| key-generation seed length key size | -//| | -//| random-to-key function identity function | -//| | -//| hash function, H SHA-1 | -//| | -//| HMAC output size, h 12 octets (96 bits) | -//| | -//| message block size, m 1 octet | -//| | -//| encryption/decryption functions, AES in CBC-CTS mode | -//| E and D (cipher block size 16 | -//| octets), with next-to- | -//| last block (last block | -//| if only one) as CBC-style | -//| ivec | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| encryption types | -//+--------------------------------------------------------------------+ -//| type name etype value key size | -//+--------------------------------------------------------------------+ -//| aes128-cts-hmac-sha1-96 17 128 | -//| aes256-cts-hmac-sha1-96 18 256 | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| checksum types | -//+--------------------------------------------------------------------+ -//| type name sumtype value length | -//+--------------------------------------------------------------------+ -//| hmac-sha1-96-aes128 15 96 | -//| hmac-sha1-96-aes256 16 96 | -//+--------------------------------------------------------------------+ // Aes128CtsHmacSha96 implements Kerberos encryption type aes128-cts-hmac-sha1-96 type Aes128CtsHmacSha96 struct { diff --git a/crypto/aes128-cts-hmac-sha256-128.go b/crypto/aes128-cts-hmac-sha256-128.go index 49a1b077..b6c9e88d 100644 --- a/crypto/aes128-cts-hmac-sha256-128.go +++ b/crypto/aes128-cts-hmac-sha256-128.go @@ -110,11 +110,8 @@ func (e Aes128CtsHmacSha256128) DeriveRandom(protocolKey, usage []byte) ([]byte, } // VerifyIntegrity checks the integrity of the ciphertext message. -// The HMAC is calculated over the cipher state concatenated with the -// AES output, instead of being calculated over the confounder and -// plaintext. This allows the message receiver to verify the -// integrity of the message before decrypting the message. -// Therefore the pt value to this interface method is not use. Pass any []byte. +// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this +// interface method is not use. Pass any []byte. func (e Aes128CtsHmacSha256128) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool { // We don't need ib just there for the interface return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e) diff --git a/crypto/aes256-cts-hmac-sha1-96.go b/crypto/aes256-cts-hmac-sha1-96.go index 0cdbb7ec..c9331245 100644 --- a/crypto/aes256-cts-hmac-sha1-96.go +++ b/crypto/aes256-cts-hmac-sha1-96.go @@ -14,50 +14,6 @@ import ( ) // RFC 3962 -//+--------------------------------------------------------------------+ -//| protocol key format 128- or 256-bit string | -//| | -//| string-to-key function PBKDF2+DK with variable | -//| iteration count (see | -//| above) | -//| | -//| default string-to-key parameters 00 00 10 00 | -//| | -//| key-generation seed length key size | -//| | -//| random-to-key function identity function | -//| | -//| hash function, H SHA-1 | -//| | -//| HMAC output size, h 12 octets (96 bits) | -//| | -//| message block size, m 1 octet | -//| | -//| encryption/decryption functions, AES in CBC-CTS mode | -//| E and D (cipher block size 16 | -//| octets), with next-to- | -//| last block (last block | -//| if only one) as CBC-style | -//| ivec | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| encryption types | -//+--------------------------------------------------------------------+ -//| type name etype value key size | -//+--------------------------------------------------------------------+ -//| aes128-cts-hmac-sha1-96 17 128 | -//| aes256-cts-hmac-sha1-96 18 256 | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| checksum types | -//+--------------------------------------------------------------------+ -//| type name sumtype value length | -//+--------------------------------------------------------------------+ -//| hmac-sha1-96-aes128 15 96 | -//| hmac-sha1-96-aes256 16 96 | -//+--------------------------------------------------------------------+ // Aes256CtsHmacSha96 implements Kerberos encryption type aes256-cts-hmac-sha1-96 type Aes256CtsHmacSha96 struct { diff --git a/crypto/aes256-cts-hmac-sha384-192.go b/crypto/aes256-cts-hmac-sha384-192.go index 562b0786..f5cdacc8 100644 --- a/crypto/aes256-cts-hmac-sha384-192.go +++ b/crypto/aes256-cts-hmac-sha384-192.go @@ -110,11 +110,8 @@ func (e Aes256CtsHmacSha384192) DeriveRandom(protocolKey, usage []byte) ([]byte, } // VerifyIntegrity checks the integrity of the ciphertext message. -// The HMAC is calculated over the cipher state concatenated with the -// AES output, instead of being calculated over the confounder and -// plaintext. This allows the message receiver to verify the -// integrity of the message before decrypting the message. -// Therefore the pt value to this interface method is not use. Pass any []byte. +// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this +// interface method is not use. Pass any []byte. func (e Aes256CtsHmacSha384192) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool { // We don't need ib just there for the interface return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e) diff --git a/crypto/common/common.go b/crypto/common/common.go index 96ae5499..7ab30a51 100644 --- a/crypto/common/common.go +++ b/crypto/common/common.go @@ -92,39 +92,28 @@ func GetIntegrityHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, e // VerifyChecksum compares the checksum of the msg bytes is the same as the checksum provided. func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool { - //The ciphertext output is the concatenation of the output of the basic - //encryption function E and a (possibly truncated) HMAC using the - //specified hash function H, both applied to the plaintext with a - //random confounder prefix and sufficient padding to bring it to a - //multiple of the message block size. When the HMAC is computed, the - //key is used in the protocol key form. + //The encrypted message is a concatenation of the encrypted output and the hash HMAC. expectedMAC, _ := GetChecksumHash(msg, key, usage, etype) return hmac.Equal(chksum, expectedMAC) } // GetUsageKc returns the checksum key usage value for the usage number un. // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Kc = DK(base-key, usage | 0x99); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKc(un uint32) []byte { return getUsage(un, 0x99) } // GetUsageKe returns the encryption key usage value for the usage number un // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Ke = DK(base-key, usage | 0xAA); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKe(un uint32) []byte { return getUsage(un, 0xAA) } // GetUsageKi returns the integrity key usage value for the usage number un // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Ki = DK(base-key, usage | 0x55); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKi(un uint32) []byte { return getUsage(un, 0x55) } diff --git a/crypto/des3-cbc-sha1-kd.go b/crypto/des3-cbc-sha1-kd.go index db3a149a..8014527a 100644 --- a/crypto/des3-cbc-sha1-kd.go +++ b/crypto/des3-cbc-sha1-kd.go @@ -15,41 +15,6 @@ import ( //RFC: 3961 Section 6.3 -/* - des3-cbc-hmac-sha1-kd, hmac-sha1-des3-kd - ------------------------------------------------ - protocol key format 24 bytes, parity in low - bit of each - - key-generation seed 21 bytes - length - - hash function SHA-1 - - HMAC output size 160 bits - - message block size 8 bytes - - default string-to-key empty string - params - - encryption and triple-DES encrypt and - decryption functions decrypt, in outer-CBC - mode (cipher block size - 8 octets) - - key generation functions: - - random-to-key DES3random-to-key (see - below) - - string-to-key DES3string-to-key (see - below) - - The des3-cbc-hmac-sha1-kd encryption type is assigned the value - sixteen (16). The hmac-sha1-des3-kd checksum algorithm is assigned a - checksum type number of twelve (12)*/ - // Des3CbcSha1Kd implements Kerberos encryption type des3-cbc-hmac-sha1-kd type Des3CbcSha1Kd struct { } diff --git a/crypto/etype/etype.go b/crypto/etype/etype.go index ee7510e2..ab1496d3 100644 --- a/crypto/etype/etype.go +++ b/crypto/etype/etype.go @@ -8,20 +8,20 @@ type EType interface { GetETypeID() int32 GetHashID() int32 GetKeyByteSize() int - GetKeySeedBitLength() int // key-generation seed length, k - GetDefaultStringToKeyParams() string // default string-to-key parameters (s2kparams) - StringToKey(string, salt, s2kparams string) ([]byte, error) // string-to-key (UTF-8 string, UTF-8 string, opaque)->(protocol-key) - RandomToKey(b []byte) []byte // random-to-key (bitstring[K])->(protocol-key) - GetHMACBitLength() int // HMAC output size, h - GetMessageBlockByteSize() int // message block size, m - EncryptData(key, data []byte) ([]byte, []byte, error) // E function - encrypt (specific-key, state, octet string)->(state, octet string) + GetKeySeedBitLength() int + GetDefaultStringToKeyParams() string + StringToKey(string, salt, s2kparams string) ([]byte, error) + RandomToKey(b []byte) []byte + GetHMACBitLength() int + GetMessageBlockByteSize() int + EncryptData(key, data []byte) ([]byte, []byte, error) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) - DecryptData(key, data []byte) ([]byte, error) // D function + DecryptData(key, data []byte) ([]byte, error) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) - GetCypherBlockBitLength() int // cipher block size, c - GetConfounderByteSize() int // This is the same as the cipher block size but in bytes. - DeriveKey(protocolKey, usage []byte) ([]byte, error) // DK key-derivation (protocol-key, integer)->(specific-key) - DeriveRandom(protocolKey, usage []byte) ([]byte, error) // DR pseudo-random (protocol-key, octet-string)->(octet-string) + GetCypherBlockBitLength() int + GetConfounderByteSize() int + DeriveKey(protocolKey, usage []byte) ([]byte, error) + DeriveRandom(protocolKey, usage []byte) ([]byte, error) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool diff --git a/crypto/rc4-hmac.go b/crypto/rc4-hmac.go index 9df55eed..d066a2c4 100644 --- a/crypto/rc4-hmac.go +++ b/crypto/rc4-hmac.go @@ -14,9 +14,7 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/iana/etypeID" ) -//http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java#ArcFourCrypto.encrypt%28byte%5B%5D%2Cint%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cint%2Cint%29 - -// RC4HMAC implements Kerberos encryption type aes256-cts-hmac-sha1-96 +// RC4HMAC implements Kerberos encryption type rc4-hmac type RC4HMAC struct { } diff --git a/crypto/rfc3961/encryption.go b/crypto/rfc3961/encryption.go index 6f550fa8..1448f6bc 100644 --- a/crypto/rfc3961/encryption.go +++ b/crypto/rfc3961/encryption.go @@ -112,12 +112,6 @@ func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([] // VerifyIntegrity verifies the integrity of cipertext bytes ct. func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool { - //The ciphertext output is the concatenation of the output of the basic - //encryption function E and a (possibly truncated) HMAC using the - //specified hash function H, both applied to the plaintext with a - //random confounder prefix and sufficient padding to bring it to a - //multiple of the message block size. When the HMAC is computed, the - //key is used in the protocol key form. h := make([]byte, etype.GetHMACBitLength()/8) copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:]) expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype) diff --git a/crypto/rfc3961/keyDerivation.go b/crypto/rfc3961/keyDerivation.go index 8c637a22..9ff115c4 100644 --- a/crypto/rfc3961/keyDerivation.go +++ b/crypto/rfc3961/keyDerivation.go @@ -10,7 +10,7 @@ const ( prfconstant = "prf" ) -// DeriveRandom implements the RFC 3961 defined function: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state)). +// DeriveRandom implements the RFC 3961 section 5.1 defined DR function // // key: base key or protocol key. Likely to be a key from a keytab file. // @@ -28,16 +28,7 @@ func DeriveRandom(key, usage []byte, e etype.EType) ([]byte, error) { nFoldUsage := Nfold(usage, n) //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8) out := make([]byte, k/8) - - /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary. - The construct is as follows (where | indicates concatenation): - - K1 = E(Key, n-fold(Constant), initial-cipher-state) - K2 = E(Key, K1, initial-cipher-state) - K3 = E(Key, K2, initial-cipher-state) - K4 = ... - - DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/ + // Keep feeding the output back into the encryption function until it is no longer short than k. _, K, err := e.EncryptData(key, nFoldUsage) if err != nil { return out, err diff --git a/crypto/rfc3961/nfold.go b/crypto/rfc3961/nfold.go index 779d1c6e..9536b1e3 100644 --- a/crypto/rfc3961/nfold.go +++ b/crypto/rfc3961/nfold.go @@ -1,27 +1,6 @@ package rfc3961 -/* -Implementation of the n-fold algorithm as defined in RFC 3961. - -n-fold is an algorithm that takes m input bits and "stretches" them -to form n output bits with equal contribution from each input bit to -the output, as described in [Blumenthal96]: - -We first define a primitive called n-folding, which takes a -variable-length input block and produces a fixed-length output -sequence. The intent is to give each input bit approximately -equal weight in determining the value of each output bit. Note -that whenever we need to treat a string of octets as a number, the -assumed representation is Big-Endian -- Most Significant Byte -first. - -To n-fold a number X, replicate the input value to a length that -is the least common multiple of n and the length of X. Before -each repetition, the input is rotated to the right by 13 bit -positions. The successive n-bit chunks are added together using -1's-complement addition (that is, with end-around carry) to yield -a n-bit result.... -*/ +// Implementation of the n-fold algorithm as defined in RFC 3961. /* Credits This golang implementation of nfold used the following project for help with implementation detail. diff --git a/crypto/rfc3962/keyDerivation.go b/crypto/rfc3962/keyDerivation.go index a5f45c1c..ea5b8b4c 100644 --- a/crypto/rfc3962/keyDerivation.go +++ b/crypto/rfc3962/keyDerivation.go @@ -35,11 +35,9 @@ func StringToKeyIter(secret, salt string, iterations int64, e etype.EType) ([]by // S2KparamsToItertions converts the string representation of iterations to an integer func S2KparamsToItertions(s2kparams string) (int64, error) { - //process s2kparams string - //The parameter string is four octets indicating an unsigned - //number in big-endian order. This is the number of iterations to be - //performed. If the value is 00 00 00 00, the number of iterations to - //be performed is 4,294,967,296 (2**32). + //The s2kparams string should be hex string representing 4 bytes + //The 4 bytes represent a number in big endian order + //If the value is zero then the number of iterations should be 4,294,967,296 (2^32) var i uint32 if len(s2kparams) != 8 { return int64(s2kParamsZero), errors.New("invalid s2kparams length") @@ -49,10 +47,5 @@ func S2KparamsToItertions(s2kparams string) (int64, error) { return int64(s2kParamsZero), errors.New("invalid s2kparams, cannot decode string to bytes") } i = binary.BigEndian.Uint32(b) - //buf := bytes.NewBuffer(b) - //err = binary.Read(buf, binary.BigEndian, &i) - if err != nil { - return int64(s2kParamsZero), errors.New("invalid s2kparams, cannot convert to big endian int32") - } return int64(i), nil } diff --git a/crypto/rfc4757/keyDerivation.go b/crypto/rfc4757/keyDerivation.go index 5e7ec480..d1f90c07 100644 --- a/crypto/rfc4757/keyDerivation.go +++ b/crypto/rfc4757/keyDerivation.go @@ -33,21 +33,6 @@ func StringToKey(secret string) ([]byte, error) { } func deriveKeys(key, checksum []byte, usage uint32, export bool) (k1, k2, k3 []byte) { - //if export { - // L40 := make([]byte, 14, 14) - // copy(L40, []byte(`fortybits`)) - // k1 = HMAC(key, L40) - //} else { - // tb := MessageTypeBytes(usage) - // k1 = HMAC(key, tb) - //} - //k2 = k1[:16] - //if export { - // mask := []byte{0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB} - // copy(k1[7:16], mask) - //} - //k3 = HMAC(k1, checksum) - //return k1 = key k2 = HMAC(k1, UsageToMSMsgType(usage)) k3 = HMAC(k2, checksum) diff --git a/crypto/rfc8009/encryption.go b/crypto/rfc8009/encryption.go index 86aae098..75c51a5f 100644 --- a/crypto/rfc8009/encryption.go +++ b/crypto/rfc8009/encryption.go @@ -108,11 +108,8 @@ func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte // GetIntegityHash returns a keyed integrity hash of the bytes provided as defined in RFC 8009 func GetIntegityHash(iv, c, key []byte, usage uint32, e etype.EType) ([]byte, error) { // Generate and append integrity hash - // The HMAC is calculated over the cipher state concatenated with the - // AES output, instead of being calculated over the confounder and - // plaintext. This allows the message receiver to verify the - // integrity of the message before decrypting the message. - // H = HMAC(Ki, IV | C) + // Rather than calculating the hash over the confounder and plaintext + // it is calculated over the iv concatenated with the AES cipher output. ib := append(iv, c...) return common.GetIntegrityHash(ib, key, usage, e) } diff --git a/crypto/rfc8009/keyDerivation.go b/crypto/rfc8009/keyDerivation.go index 90ced3b5..b24e5a5c 100644 --- a/crypto/rfc8009/keyDerivation.go +++ b/crypto/rfc8009/keyDerivation.go @@ -24,16 +24,6 @@ func DeriveRandom(protocolKey, usage []byte, e etype.EType) ([]byte, error) { // DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods. // // https://tools.ietf.org/html/rfc8009#section-5 -// -// If the enctype is aes128-cts-hmac-sha256-128: -// Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 128) -// Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 128) -// Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 128) -// -// If the enctype is aes256-cts-hmac-sha384-192: -// Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 192) -// Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 256) -// Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 192) func DeriveKey(protocolKey, label []byte, e etype.EType) []byte { var context []byte var kl int diff --git a/gssapi/MICToken.go b/gssapi/MICToken.go index 856412ba..c574710e 100644 --- a/gssapi/MICToken.go +++ b/gssapi/MICToken.go @@ -13,32 +13,7 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/* -From RFC 4121, section 4.2.6.1: - - Use of the GSS_GetMIC() call yields a token (referred as the MIC - token in this document), separate from the user data being protected, - which can be used to verify the integrity of that data as received. - The token has the following format: - - Octet no Name Description - -------------------------------------------------------------- - 0..1 TOK_ID Identification field. Tokens emitted by - GSS_GetMIC() contain the hex value 04 04 - expressed in big-endian order in this - field. - 2 Flags Attributes field, as described in section - 4.2.2. - 3..7 Filler Contains five octets of hex value FF. - 8..15 SND_SEQ Sequence number field in clear text, - expressed in big-endian order. - 16..last SGN_CKSUM Checksum of the "to-be-signed" data and - octet 0..15, as described in section 4.2.4. - - The Filler field is included in the checksum calculation for - simplicity. - -*/ +// RFC 4121, section 4.2.6.1 const ( // MICTokenFlagSentByAcceptor - this flag indicates the sender is the context acceptor. When not set, it indicates the sender is the context initiator @@ -106,9 +81,6 @@ func (mt *MICToken) SetChecksum(key types.EncryptionKey, keyUsage uint32) error } // Compute and return the checksum of this token, computed using the passed key and key usage. -// Confirms to RFC 4121 in that the checksum will be computed over { body | header }. -// In the context of Kerberos MIC tokens, mostly keyusage GSSAPI_ACCEPTOR_SIGN (=23) -// and GSSAPI_INITIATOR_SIGN (=25) will be used. // Note: This will NOT update the struct's Checksum field. func (mt *MICToken) checksum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) { if mt.Payload == nil { diff --git a/gssapi/wrapToken.go b/gssapi/wrapToken.go index 9dbf96ba..33d239d7 100644 --- a/gssapi/wrapToken.go +++ b/gssapi/wrapToken.go @@ -13,46 +13,8 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/* -From RFC 4121, section 4.2.6.2: - - Use of the GSS_Wrap() call yields a token (referred as the Wrap token - in this document), which consists of a descriptive header, followed - by a body portion that contains either the input user data in - plaintext concatenated with the checksum, or the input user data - encrypted. The GSS_Wrap() token SHALL have the following format: - - Octet no Name Description - -------------------------------------------------------------- - 0..1 TOK_ID Identification field. Tokens emitted by - GSS_Wrap() contain the hex value 05 04 - expressed in big-endian order in this - field. - 2 Flags Attributes field, as described in section - 4.2.2. - 3 Filler Contains the hex value FF. - 4..5 EC Contains the "extra count" field, in big- - endian order as described in section 4.2.3. - 6..7 RRC Contains the "right rotation count" in big- - endian order, as described in section - 4.2.5. - 8..15 SndSeqNum Sequence number field in clear text, - expressed in big-endian order. - 16..last Data Encrypted data for Wrap tokens with - confidentiality, or plaintext data followed - by the checksum for Wrap tokens without - confidentiality, as described in section - 4.2.4. - -Quick notes: - - "EC" or "Extra Count" refers to the length of the checksum. - - "Flags" (complete details in section 4.2.2) is a set of bits: - - if bit 0 is set, it means the token was sent by the acceptor (generally the kerberized service). - - bit 1 indicates that the token's payload is encrypted - - bit 2 indicates if the message is protected using a subkey defined by the acceptor. - - When computing checksums, EC and RRC MUST be set to 0. - - Wrap Tokens are not ASN.1 encoded. -*/ +// RFC 4121, section 4.2.6.2 + const ( HdrLen = 16 // Length of the Wrap Token's header FillerByte byte = 0xFF @@ -121,10 +83,6 @@ func (wt *WrapToken) SetCheckSum(key types.EncryptionKey, keyUsage uint32) error } // ComputeCheckSum computes and returns the checksum of this token, computed using the passed key and key usage. -// Conforms to RFC 4121 in that the checksum will be computed over { body | header }, -// with the EC and RRC flags zeroed out. -// In the context of Kerberos Wrap tokens, mostly keyusage GSSAPI_ACCEPTOR_SEAL (=22) -// and GSSAPI_INITIATOR_SEAL (=24) will be used. // Note: This will NOT update the struct's Checksum field. func (wt *WrapToken) computeCheckSum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) { if wt.Payload == nil { diff --git a/keytab/keytab.go b/keytab/keytab.go index 22c02044..dd85130c 100644 --- a/keytab/keytab.go +++ b/keytab/keytab.go @@ -161,12 +161,6 @@ func (kt *Keytab) Unmarshal(b []byte) error { if kt.version == 1 && isNativeEndianLittle() { endian = binary.LittleEndian } - /* - After the two-byte version indicator, the file contains a sequence of signed 32-bit record lengths followed by key records or holes. - A positive record length indicates a valid key entry whose size is equal to or less than the record length. - A negative length indicates a zero-filled hole whose size is the inverse of the length. - A length of 0 indicates the end of the file. - */ // n tracks position in the byte array n := 2 l, err := readInt32(b, &n, &endian) @@ -179,7 +173,6 @@ func (kt *Keytab) Unmarshal(b []byte) error { l = l * -1 n = n + int(l) } else { - //fmt.Printf("Bytes for entry: %v\n", b[n:n+int(l)]) if n < 0 { return fmt.Errorf("%d can't be less than zero", n) } @@ -216,9 +209,9 @@ func (kt *Keytab) Unmarshal(b []byte) error { if err != nil { return err } - //The 32-bit key version overrides the 8-bit key version. - // To determine if it is present, the implementation must check that at least 4 bytes remain in the record after the other fields are read, - // and that the value of the 32-bit integer contained in those bytes is non-zero. + // The 32-bit key version overrides the 8-bit key version. + // If at least 4 bytes are left after the other fields are read and they are non-zero + // this indicates the 32-bit version is present. if len(eb)-p >= 4 { // The 32-bit key may be present ri32, err := readInt32(eb, &p, &endian) diff --git a/messages/APRep.go b/messages/APRep.go index 9c244f07..8e4049a0 100644 --- a/messages/APRep.go +++ b/messages/APRep.go @@ -11,21 +11,6 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/* -AP-REP ::= [APPLICATION 15] SEQUENCE { -pvno [0] INTEGER (5), -msg-type [1] INTEGER (15), -enc-part [2] EncryptedData -- EncAPRepPart -} - -EncAPRepPart ::= [APPLICATION 27] SEQUENCE { - ctime [0] KerberosTime, - cusec [1] Microseconds, - subkey [2] EncryptionKey OPTIONAL, - seq-number [3] UInt32 OPTIONAL -} -*/ - // APRep implements RFC 4120 KRB_AP_REP: https://tools.ietf.org/html/rfc4120#section-5.5.2. type APRep struct { PVNO int `asn1:"explicit,tag:0"` diff --git a/messages/APReq.go b/messages/APReq.go index e1ed4ae1..1484e131 100644 --- a/messages/APReq.go +++ b/messages/APReq.go @@ -17,19 +17,6 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/*AP-REQ ::= [APPLICATION 14] SEQUENCE { -pvno [0] INTEGER (5), -msg-type [1] INTEGER (14), -ap-options [2] APOptions, -ticket [3] Ticket, -authenticator [4] EncryptedData -- Authenticator -} - -APOptions ::= KerberosFlags --- reserved(0), --- use-session-key(1), --- mutual-required(2)*/ - type marshalAPReq struct { PVNO int `asn1:"explicit,tag:0"` MsgType int `asn1:"explicit,tag:1"` @@ -82,7 +69,6 @@ func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey, } // DecryptAuthenticator decrypts the Authenticator within the AP_REQ. -// sessionKey may simply be the key within the decrypted EncPart of the ticket within the AP_REQ. func (a *APReq) DecryptAuthenticator(sessionKey types.EncryptionKey) error { usage := authenticatorKeyUsage(a.Ticket.SName) ab, e := crypto.DecryptEncPart(a.EncryptedAuthenticator, sessionKey, uint32(usage)) @@ -157,22 +143,11 @@ func (a *APReq) Verify(kt *keytab.Keytab, d time.Duration, cAddr types.HostAddre // Decrypt ticket's encrypted part with service key //TODO decrypt with service's session key from its TGT is use-to-user. Need to figure out how to get TGT. //if types.IsFlagSet(&a.APOptions, flags.APOptionUseSessionKey) { - // //If the USE-SESSION-KEY flag is set in the ap-options field, it indicates to - // //the server that user-to-user authentication is in use, and that the ticket - // //is encrypted in the session key from the server's TGT rather than in the server's secret key. // err := a.Ticket.Decrypt(tgt.DecryptedEncPart.Key) // if err != nil { // return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of ticket provided using session key") // } //} else { - // // Because it is possible for the server to be registered in multiple - // // realms, with different keys in each, the srealm field in the - // // unencrypted portion of the ticket in the KRB_AP_REQ is used to - // // specify which secret key the server should use to decrypt that - // // ticket.The KRB_AP_ERR_NOKEY error code is returned if the server - // // doesn't have the proper key to decipher the ticket. - // // The ticket is decrypted using the version of the server's key - // // specified by the ticket. // err := a.Ticket.DecryptEncPart(*kt, &a.Ticket.SName) // if err != nil { // return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of service ticket provided") @@ -191,9 +166,8 @@ func (a *APReq) Verify(kt *keytab.Keytab, d time.Duration, cAddr types.HostAddre // Check client's address is listed in the client addresses in the ticket if len(a.Ticket.DecryptedEncPart.CAddr) > 0 { - //The addresses in the ticket (if any) are then searched for an address matching the operating-system reported - //address of the client. If no match is found or the server insists on ticket addresses but none are present in - //the ticket, the KRB_AP_ERR_BADADDR error is returned. + //If client addresses are present check if any of them match the source IP that sent the APReq + //If there is no match return KRB_AP_ERR_BADADDR error. if !types.HostAddressesContains(a.Ticket.DecryptedEncPart.CAddr, cAddr) { return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "client address not within the list contained in the service ticket") } diff --git a/messages/KDCRep.go b/messages/KDCRep.go index 76c89c34..4d918e65 100644 --- a/messages/KDCRep.go +++ b/messages/KDCRep.go @@ -135,12 +135,8 @@ func (e *EncKDCRepPart) Unmarshal(b []byte) error { _, err := asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncASRepPart)) if err != nil { // Try using tag 26 - /* Ref: RFC 4120 - Compatibility note: Some implementations unconditionally send an - encrypted EncTGSRepPart (application tag number 26) in this field - regardless of whether the reply is a AS-REP or a TGS-REP. In the - interest of compatibility, implementors MAY relax the check on the - tag number of the decrypted ENC-PART.*/ + // Ref: RFC 4120 - mentions that some implementations use application tag number 26 wether or not the reply is + // a AS-REP or a TGS-REP. _, err = asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncTGSRepPart)) if err != nil { return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part within KDC_REP") diff --git a/messages/KRBSafe.go b/messages/KRBSafe.go index 9c5acc1d..ce8e2ba7 100644 --- a/messages/KRBSafe.go +++ b/messages/KRBSafe.go @@ -11,24 +11,6 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/* -KRB-SAFE ::= [APPLICATION 20] SEQUENCE { - pvno [0] INTEGER (5), - msg-type [1] INTEGER (20), - safe-body [2] KRB-SAFE-BODY, - cksum [3] Checksum -} - -KRB-SAFE-BODY ::= SEQUENCE { - user-data [0] OCTET STRING, - timestamp [1] KerberosTime OPTIONAL, - usec [2] Microseconds OPTIONAL, - seq-number [3] UInt32 OPTIONAL, - s-address [4] HostAddress, - r-address [5] HostAddress OPTIONAL -} -*/ - // KRBSafe implements RFC 4120 KRB_SAFE: https://tools.ietf.org/html/rfc4120#section-5.6.1. type KRBSafe struct { PVNO int `asn1:"explicit,tag:0"` diff --git a/pac/credentials_info.go b/pac/credentials_info.go index a8c2c3ca..89f08b7d 100644 --- a/pac/credentials_info.go +++ b/pac/credentials_info.go @@ -66,10 +66,6 @@ func (c *CredentialsInfo) DecryptEncPart(k types.EncryptionKey) error { } // CredentialData implements https://msdn.microsoft.com/en-us/library/cc237952.aspx -// This structure is encrypted prior to being encoded in any other structures. -// Encryption is performed by first serializing the data structure via Network Data Representation (NDR) encoding, as specified in [MS-RPCE]. -// Once serialized, the data is encrypted using the key and cryptographic system selected through the AS protocol and the KRB_AS_REP message -// Fields (for capturing this information) and cryptographic parameters are specified in PAC_CREDENTIAL_INFO (section 2.6.1). type CredentialData struct { CredentialCount uint32 Credentials []SECPKGSupplementalCred // Size is the value of CredentialCount diff --git a/pac/kerb_validation_info.go b/pac/kerb_validation_info.go index 9dd69d2b..363d8c26 100644 --- a/pac/kerb_validation_info.go +++ b/pac/kerb_validation_info.go @@ -26,11 +26,6 @@ const ( ) // KerbValidationInfo implement https://msdn.microsoft.com/en-us/library/cc237948.aspx -// The KERB_VALIDATION_INFO structure defines the user's logon and authorization information -// provided by the DC. The KERB_VALIDATION_INFO structure is a subset of the -// NETLOGON_VALIDATION_SAM_INFO4 structure ([MS-NRPC] section 2.2.1.4.13). -// It is a subset due to historical reasons and to the use of the common Active Directory to generate this information. -// The KERB_VALIDATION_INFO structure is marshaled by RPC [MS-RPCE]. type KerbValidationInfo struct { LogOnTime mstypes.FileTime LogOffTime mstypes.FileTime diff --git a/pac/signature_data.go b/pac/signature_data.go index 7e0fce1a..c2b1b594 100644 --- a/pac/signature_data.go +++ b/pac/signature_data.go @@ -14,21 +14,9 @@ The Key Usage Value MUST be KERB_NON_KERB_CKSUM_SALT (17) [MS-KILE] (section 3.1 Server Signature (SignatureType = 0x00000006) https://msdn.microsoft.com/en-us/library/cc237957.aspx -The KDC will use the long-term key that the KDC shares with the server, so that the server can verify this signature on receiving a PAC. -The server signature is a keyed hash [RFC4757] of the entire PAC message, with the Signature fields of both PAC_SIGNATURE_DATA structures set to zero. -The key used to protect the ciphertext part of the response is used. -The checksum type corresponds to the key unless the key is DES, in which case the KERB_CHECKSUM_HMAC_MD5 key is used. -The resulting hash value is then placed in the Signature field of the server's PAC_SIGNATURE_DATA structure. KDC Signature (SignatureType = 0x00000007) https://msdn.microsoft.com/en-us/library/dd357117.aspx -The KDC will use KDC (krbtgt) key [RFC4120], so that other KDCs can verify this signature on receiving a PAC. -The KDC signature is a keyed hash [RFC4757] of the Server Signature field in the PAC message. -The cryptographic system that is used to calculate the checksum depends on which system the KDC supports, as defined below: -- Supports RC4-HMAC --> KERB_CHECKSUM_HMAC_MD5 -- Does not support RC4-HMAC and supports AES256 --> HMAC_SHA1_96_AES256 -- Does not support RC4-HMAC or AES256-CTS-HMAC-SHA1-96, and supports AES128-CTS-HMAC-SHA1-96 --> HMAC_SHA1_96_AES128 -- Does not support RC4-HMAC, AES128-CTS-HMAC-SHA1-96 or AES256-CTS-HMAC-SHA1-96 --> None. The checksum operation will fail. */ // SignatureData implements https://msdn.microsoft.com/en-us/library/cc237955.aspx diff --git a/pac/supplemental_cred.go b/pac/supplemental_cred.go index 5f4f93c2..d2eb6880 100644 --- a/pac/supplemental_cred.go +++ b/pac/supplemental_cred.go @@ -70,9 +70,6 @@ func isFlagSet(f uint32, i uint32) bool { } // SECPKGSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237956.aspx -// The SECPKG_SUPPLEMENTAL_CRED structure defines the name of the security package that requires -// supplemental credentials and the credential buffer for that package. -// The SECPKG_SUPPLEMENTAL_CRED structure is marshaled by RPC. type SECPKGSupplementalCred struct { PackageName mstypes.RPCUnicodeString CredentialSize uint32 diff --git a/service/cache.go b/service/cache.go index c8447493..5c293304 100644 --- a/service/cache.go +++ b/service/cache.go @@ -7,27 +7,7 @@ import ( "time" ) -/*The server MUST utilize a replay cache to remember any authenticator -presented within the allowable clock skew. -The replay cache will store at least the server name, along with the -client name, time, and microsecond fields from the recently-seen -authenticators, and if a matching tuple is found, the -KRB_AP_ERR_REPEAT error is returned. Note that the rejection here is -restricted to authenticators from the same principal to the same -server. Other client principals communicating with the same server -principal should not have their authenticators rejected if the time -and microsecond fields happen to match some other client's -authenticator. - -If a server loses track of authenticators presented within the -allowable clock skew, it MUST reject all requests until the clock -skew interval has passed, providing assurance that any lost or -replayed authenticators will fall outside the allowable clock skew -and can no longer be successfully replayed. If this were not done, -an attacker could subvert the authentication by recording the ticket -and authenticator sent over the network to a server and replaying -them following an event that caused the server to lose track of -recently seen authenticators.*/ +// Replay cache is required as specified in RFC 4120 section 3.2.3 // Cache for tickets received from clients keyed by fully qualified client name. Used to track replay of tickets. type Cache struct { diff --git a/spnego/krb5Token.go b/spnego/krb5Token.go index 73bd64d1..fd3261a6 100644 --- a/spnego/krb5Token.go +++ b/spnego/krb5Token.go @@ -217,26 +217,3 @@ func newAuthenticatorChksum(flags []int) []byte { } return a } - -/* -The authenticator checksum field SHALL have the following format: - -Octet Name Description ------------------------------------------------------------------ -0..3 Lgth Number of octets in Bnd field; Represented - in little-endian order; Currently contains - hex value 10 00 00 00 (16). -4..19 Bnd Channel binding information, as described in - section 4.1.1.2. -20..23 Flags Four-octet context-establishment flags in - little-endian order as described in section - 4.1.1.1. -24..25 DlgOpt The delegation option identifier (=1) in - little-endian order [optional]. This field - and the next two fields are present if and - only if GSS_C_DELEG_FLAG is set as described - in section 4.1.1.1. -26..27 Dlgth The length of the Deleg field in little-endian order [optional]. -28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional]. -n..last Exts Extensions [optional]. -*/ diff --git a/spnego/negotiationToken.go b/spnego/negotiationToken.go index 34d305f3..0edd5a53 100644 --- a/spnego/negotiationToken.go +++ b/spnego/negotiationToken.go @@ -13,39 +13,7 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/types" ) -/* -https://msdn.microsoft.com/en-us/library/ms995330.aspx - -NegotiationToken ::= CHOICE { - negTokenInit [0] NegTokenInit, This is the Negotiation token sent from the client to the server. - negTokenResp [1] NegTokenResp -} - -NegTokenInit ::= SEQUENCE { - mechTypes [0] MechTypeList, - reqFlags [1] ContextFlags OPTIONAL, - -- inherited from RFC 2478 for backward compatibility, - -- RECOMMENDED to be left out - mechToken [2] OCTET STRING OPTIONAL, - mechListMIC [3] OCTET STRING OPTIONAL, - ... -} - -NegTokenResp ::= SEQUENCE { - negState [0] ENUMERATED { - accept-completed (0), - accept-incomplete (1), - reject (2), - request-mic (3) - } OPTIONAL, - -- REQUIRED in the first reply from the target - supportedMech [1] MechType OPTIONAL, - -- present only in the first reply from the target - responseToken [2] OCTET STRING OPTIONAL, - mechListMIC [3] OCTET STRING OPTIONAL, - ... -} -*/ +// https://msdn.microsoft.com/en-us/library/ms995330.aspx // Negotiation state values. const ( diff --git a/types/Authenticator.go b/types/Authenticator.go index 500e0346..720c1383 100644 --- a/types/Authenticator.go +++ b/types/Authenticator.go @@ -14,27 +14,8 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/iana/asnAppTag" ) -/*Authenticator ::= [APPLICATION 2] SEQUENCE { -authenticator-vno [0] INTEGER (5), -crealm [1] Realm, -cname [2] PrincipalName, -cksum [3] Checksum OPTIONAL, -cusec [4] Microseconds, -ctime [5] KerberosTime, -subkey [6] EncryptionKey OPTIONAL, -seq-number [7] UInt32 OPTIONAL, -authorization-data [8] AuthorizationData OPTIONAL -} - - cksum - This field contains a checksum of the application data that - accompanies the KRB_AP_REQ, computed using a key usage value of 10 - in normal application exchanges, or 6 when used in the TGS-REQ - PA-TGS-REQ AP-DATA field. - -*/ - -// Authenticator - A record containing information that can be shown to have been recently generated using the session key known only by the client and server. +// Authenticator - A record containing information that can be shown to have been recently generated using the session +// key known only by the client and server. // https://tools.ietf.org/html/rfc4120#section-5.5.1 type Authenticator struct { AVNO int `asn1:"explicit,tag:0"` diff --git a/types/AuthorizationData.go b/types/AuthorizationData.go index c9448008..80c477ce 100644 --- a/types/AuthorizationData.go +++ b/types/AuthorizationData.go @@ -7,74 +7,6 @@ import ( // Reference: https://www.ietf.org/rfc/rfc4120.txt // Section: 5.2.6 -/* -AuthorizationData - --- NOTE: AuthorizationData is always used as an OPTIONAL field and --- should not be empty. -AuthorizationData ::= SEQUENCE OF SEQUENCE { -ad-type [0] Int32, -ad-data [1] OCTET STRING -} - -ad-data -This field contains authorization data to be interpreted according -to the value of the corresponding ad-type field. - -ad-type - This field specifies the format for the ad-data subfield. All -negative values are reserved for local use. Non-negative values -are reserved for registered use. - -Each sequence of type and data is referred to as an authorization -element. Elements MAY be application specific; however, there is a -common set of recursive elements that should be understood by all -implementations. These elements contain other elements embedded -within them, and the interpretation of the encapsulating element -determines which of the embedded elements must be interpreted, and -which may be ignored. - -These common authorization data elements are recursively defined, -meaning that the ad-data for these types will itself contain a -sequence of authorization data whose interpretation is affected by -the encapsulating element. Depending on the meaning of the -encapsulating element, the encapsulated elements may be ignored, -might be interpreted as issued directly by the KDC, or might be -stored in a separate plaintext part of the ticket. The types of the -encapsulating elements are specified as part of the Kerberos -specification because the behavior based on these values should be -understood across implementations, whereas other elements need only -be understood by the applications that they affect. - -Authorization data elements are considered critical if present in a -ticket or authenticator. If an unknown authorization data element -type is received by a server either in an AP-REQ or in a ticket -contained in an AP-REQ, then, unless it is encapsulated in a known -authorization data element amending the criticality of the elements -it contains, authentication MUST fail. Authorization data is -intended to restrict the use of a ticket. If the service cannot -determine whether the restriction applies to that service, then a -security weakness may result if the ticket can be used for that -service. Authorization elements that are optional can be enclosed in -an AD-IF-RELEVANT element. - -In the definitions that follow, the value of the ad-type for the -element will be specified as the least significant part of the -subsection number, and the value of the ad-data will be as shown in -the ASN.1 structure that follows the subsection heading. - - Contents of ad-data ad-type - - DER encoding of AD-IF-RELEVANT 1 - - DER encoding of AD-KDCIssued 4 - - DER encoding of AD-AND-OR 5 - - DER encoding of AD-MANDATORY-FOR-KDC 8 - -*/ - // AuthorizationData implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.6 type AuthorizationData []AuthorizationDataEntry diff --git a/types/HostAddress.go b/types/HostAddress.go index 2f6a5a7c..5396cb21 100644 --- a/types/HostAddress.go +++ b/types/HostAddress.go @@ -12,30 +12,6 @@ import ( "gopkg.in/jcmturner/gokrb5.v7/iana/addrtype" ) -/* -HostAddress and HostAddresses - -HostAddress ::= SEQUENCE { - addr-type [0] Int32, - address [1] OCTET STRING -} - --- NOTE: HostAddresses is always used as an OPTIONAL field and --- should not be empty. -HostAddresses -- NOTE: subtly different from rfc1510, - -- but has a value mapping and encodes the same - ::= SEQUENCE OF HostAddress - -The host address encodings consist of two fields: - -addr-type - This field specifies the type of address that follows. Pre- - defined values for this field are specified in Section 7.5.3. - -address - This field encodes a single address of type addr-type. -*/ - // HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5 type HostAddresses []HostAddress diff --git a/types/KerberosFlags.go b/types/KerberosFlags.go index bd75d5b5..0f203834 100644 --- a/types/KerberosFlags.go +++ b/types/KerberosFlags.go @@ -7,62 +7,6 @@ import ( "github.com/jcmturner/gofork/encoding/asn1" ) -/* -KerberosFlags - -For several message types, a specific constrained bit string type, -KerberosFlags, is used. - -KerberosFlags ::= BIT STRING (SIZE (32..MAX)) --- minimum number of bits shall be sent, --- but no fewer than 32 - -Compatibility note: The following paragraphs describe a change from -the RFC 1510 description of bit strings that would result in -incompatility in the case of an implementation that strictly -conformed to ASN.1 DER and RFC 1510. - -ASN.1 bit strings have multiple uses. The simplest use of a bit -string is to contain a vector of bits, with no particular meaning -attached to individual bits. This vector of bits is not necessarily -a multiple of eight bits long. The use in Kerberos of a bit string -as a compact boolean vector wherein each element has a distinct -meaning poses some problems. The natural notation for a compact -boolean vector is the ASN.1 "NamedBit" notation, and the DER require -that encodings of a bit string using "NamedBit" notation exclude any -trailing zero bits. This truncation is easy to neglect, especially -given C language implementations that naturally choose to store -boolean vectors as 32-bit integers. - -For example, if the notation for KDCOptions were to include the -"NamedBit" notation, as in RFC 1510, and a KDCOptions value to be -encoded had only the "forwardable" (bit number one) bit set, the DER -encoding MUST include only two bits: the first reserved bit -("reserved", bit number zero, value zero) and the one-valued bit (bit -number one) for "forwardable". - -Most existing implementations of Kerberos unconditionally send 32 -bits on the wire when encoding bit strings used as boolean vectors. -This behavior violates the ASN.1 syntax used for flag values in RFC -1510, but it occurs on such a widely installed base that the protocol -description is being modified to accommodate it. - -Consequently, this document removes the "NamedBit" notations for -individual bits, relegating them to comments. The size constraint on -the KerberosFlags type requires that at least 32 bits be encoded at -all times, though a lenient implementation MAY choose to accept fewer -than 32 bits and to treat the missing bits as set to zero. - -Currently, no uses of KerberosFlags specify more than 32 bits' worth -of flags, although future revisions of this document may do so. When -more than 32 bits are to be transmitted in a KerberosFlags value, -future revisions to this document will likely specify that the -smallest number of bits needed to encode the highest-numbered one- -valued bit should be sent. This is somewhat similar to the DER -encoding of a bit string that is declared with the "NamedBit" -notation. -*/ - // NewKrbFlags returns an ASN1 BitString struct of the right size for KrbFlags. func NewKrbFlags() asn1.BitString { f := asn1.BitString{} diff --git a/v8/README.md b/v8/README.md index 5fb8fa9c..48b4d54a 100644 --- a/v8/README.md +++ b/v8/README.md @@ -11,9 +11,9 @@ Development will be focused on the latest major version. New features will only #### Go Version Support +![Go version](https://img.shields.io/badge/Go-1.14-brightgreen.svg) ![Go version](https://img.shields.io/badge/Go-1.13-brightgreen.svg) ![Go version](https://img.shields.io/badge/Go-1.12-brightgreen.svg) -![Go version](https://img.shields.io/badge/Go-1.11-brightgreen.svg) gokrb5 may work with other versions of Go but they are not tested. diff --git a/v8/client/ASExchange.go b/v8/client/ASExchange.go index e9cc49c6..5becccc4 100644 --- a/v8/client/ASExchange.go +++ b/v8/client/ASExchange.go @@ -145,15 +145,7 @@ func setPAData(cl *Client, krberr *messages.KRBError, ASReq *messages.ASReq) err // preAuthEType establishes what encryption type to use for pre-authentication from the KRBError returned from the KDC. func preAuthEType(krberr *messages.KRBError) (etype etype.EType, err error) { - //The preferred ordering of the "hint" pre-authentication data that - //affect client key selection is: ETYPE-INFO2, followed by ETYPE-INFO, - //followed by PW-SALT. - //A KDC SHOULD NOT send PA-PW-SALT when issuing a KRB-ERROR message - //that requests additional pre-authentication. Implementation note: - //Some KDC implementations issue an erroneous PA-PW-SALT when issuing a - //KRB-ERROR message that requests additional pre-authentication. - //Therefore, clients SHOULD ignore a PA-PW-SALT accompanying a - //KRB-ERROR message that requests additional pre-authentication. + //RFC 4120 5.2.7.5 covers the preference order of ETYPE-INFO2 and ETYPE-INFO. var etypeID int32 var pas types.PADataSequence e := pas.Unmarshal(krberr.EData) diff --git a/v8/client/network.go b/v8/client/network.go index b5680230..9ca0e37a 100644 --- a/v8/client/network.go +++ b/v8/client/network.go @@ -172,18 +172,7 @@ func (cl *Client) sendUDP(conn *net.UDPConn, b []byte) ([]byte, error) { func (cl *Client) sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) { defer conn.Close() var r []byte - /* - RFC https://tools.ietf.org/html/rfc4120#section-7.2.2 - Each request (KRB_KDC_REQ) and response (KRB_KDC_REP or KRB_ERROR) - sent over the TCP stream is preceded by the length of the request as - 4 octets in network byte order. The high bit of the length is - reserved for future expansion and MUST currently be set to zero. If - a KDC that does not understand how to interpret a set high bit of the - length encoding receives a request with the high order bit of the - length set, it MUST return a KRB-ERROR message with the error - KRB_ERR_FIELD_TOOLONG and MUST close the TCP stream. - NB: network byte order == big endian - */ + // RFC 4120 7.2.2 specifies the first 4 bytes indicate the length of the message in big endian order. var buf bytes.Buffer err := binary.Write(&buf, binary.BigEndian, uint32(len(b))) if err != nil { diff --git a/v8/credentials/ccache.go b/v8/credentials/ccache.go index b7e54689..c3b35c77 100644 --- a/v8/credentials/ccache.go +++ b/v8/credentials/ccache.go @@ -17,15 +17,6 @@ const ( headerFieldTagKDCOffset = 1 ) -// The first byte of the file always has the value 5. -// The value of the second byte contains the version number (1 through 4) -// Versions 1 and 2 of the file format use native byte order for integer representations. -// Versions 3 and 4 always use big-endian byte order -// After the two-byte version indicator, the file has three parts: -// 1) the header (in version 4 only) -// 2) the default principal name -// 3) a sequence of credentials - // CCache is the file credentials cache as define here: https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html type CCache struct { Version uint8 @@ -257,13 +248,7 @@ func (c *CCache) GetEntries() []*Credential { } func (h *headerField) valid() bool { - // At this time there is only one defined header field. - // Its tag value is 1, its length is always 8. - // Its contents are two 32-bit integers giving the seconds and microseconds - // of the time offset of the KDC relative to the client. - // Adding this offset to the current time on the client should give the current time on the KDC, if that offset has not changed since the initial authentication. - - // Done as a switch in case other tag values are added in the future. + // See https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html - Header format switch h.tag { case headerFieldTagKDCOffset: if h.length != 8 || len(h.value) != 8 { diff --git a/v8/crypto/aes128-cts-hmac-sha1-96.go b/v8/crypto/aes128-cts-hmac-sha1-96.go index 081c0d73..dd8babd5 100644 --- a/v8/crypto/aes128-cts-hmac-sha1-96.go +++ b/v8/crypto/aes128-cts-hmac-sha1-96.go @@ -14,50 +14,6 @@ import ( ) // RFC 3962 -//+--------------------------------------------------------------------+ -//| protocol key format 128- or 256-bit string | -//| | -//| string-to-key function PBKDF2+DK with variable | -//| iteration count (see | -//| above) | -//| | -//| default string-to-key parameters 00 00 10 00 | -//| | -//| key-generation seed length key size | -//| | -//| random-to-key function identity function | -//| | -//| hash function, H SHA-1 | -//| | -//| HMAC output size, h 12 octets (96 bits) | -//| | -//| message block size, m 1 octet | -//| | -//| encryption/decryption functions, AES in CBC-CTS mode | -//| E and D (cipher block size 16 | -//| octets), with next-to- | -//| last block (last block | -//| if only one) as CBC-style | -//| ivec | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| encryption types | -//+--------------------------------------------------------------------+ -//| type name etype value key size | -//+--------------------------------------------------------------------+ -//| aes128-cts-hmac-sha1-96 17 128 | -//| aes256-cts-hmac-sha1-96 18 256 | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| checksum types | -//+--------------------------------------------------------------------+ -//| type name sumtype value length | -//+--------------------------------------------------------------------+ -//| hmac-sha1-96-aes128 15 96 | -//| hmac-sha1-96-aes256 16 96 | -//+--------------------------------------------------------------------+ // Aes128CtsHmacSha96 implements Kerberos encryption type aes128-cts-hmac-sha1-96 type Aes128CtsHmacSha96 struct { diff --git a/v8/crypto/aes128-cts-hmac-sha256-128.go b/v8/crypto/aes128-cts-hmac-sha256-128.go index a6a51294..b05af7d3 100644 --- a/v8/crypto/aes128-cts-hmac-sha256-128.go +++ b/v8/crypto/aes128-cts-hmac-sha256-128.go @@ -110,11 +110,8 @@ func (e Aes128CtsHmacSha256128) DeriveRandom(protocolKey, usage []byte) ([]byte, } // VerifyIntegrity checks the integrity of the ciphertext message. -// The HMAC is calculated over the cipher state concatenated with the -// AES output, instead of being calculated over the confounder and -// plaintext. This allows the message receiver to verify the -// integrity of the message before decrypting the message. -// Therefore the pt value to this interface method is not use. Pass any []byte. +// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this +// interface method is not use. Pass any []byte. func (e Aes128CtsHmacSha256128) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool { // We don't need ib just there for the interface return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e) diff --git a/v8/crypto/aes256-cts-hmac-sha1-96.go b/v8/crypto/aes256-cts-hmac-sha1-96.go index 46a2b649..45e439a4 100644 --- a/v8/crypto/aes256-cts-hmac-sha1-96.go +++ b/v8/crypto/aes256-cts-hmac-sha1-96.go @@ -14,50 +14,6 @@ import ( ) // RFC 3962 -//+--------------------------------------------------------------------+ -//| protocol key format 128- or 256-bit string | -//| | -//| string-to-key function PBKDF2+DK with variable | -//| iteration count (see | -//| above) | -//| | -//| default string-to-key parameters 00 00 10 00 | -//| | -//| key-generation seed length key size | -//| | -//| random-to-key function identity function | -//| | -//| hash function, H SHA-1 | -//| | -//| HMAC output size, h 12 octets (96 bits) | -//| | -//| message block size, m 1 octet | -//| | -//| encryption/decryption functions, AES in CBC-CTS mode | -//| E and D (cipher block size 16 | -//| octets), with next-to- | -//| last block (last block | -//| if only one) as CBC-style | -//| ivec | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| encryption types | -//+--------------------------------------------------------------------+ -//| type name etype value key size | -//+--------------------------------------------------------------------+ -//| aes128-cts-hmac-sha1-96 17 128 | -//| aes256-cts-hmac-sha1-96 18 256 | -//+--------------------------------------------------------------------+ -// -//+--------------------------------------------------------------------+ -//| checksum types | -//+--------------------------------------------------------------------+ -//| type name sumtype value length | -//+--------------------------------------------------------------------+ -//| hmac-sha1-96-aes128 15 96 | -//| hmac-sha1-96-aes256 16 96 | -//+--------------------------------------------------------------------+ // Aes256CtsHmacSha96 implements Kerberos encryption type aes256-cts-hmac-sha1-96 type Aes256CtsHmacSha96 struct { diff --git a/v8/crypto/aes256-cts-hmac-sha384-192.go b/v8/crypto/aes256-cts-hmac-sha384-192.go index 1b61022a..6a544759 100644 --- a/v8/crypto/aes256-cts-hmac-sha384-192.go +++ b/v8/crypto/aes256-cts-hmac-sha384-192.go @@ -110,11 +110,8 @@ func (e Aes256CtsHmacSha384192) DeriveRandom(protocolKey, usage []byte) ([]byte, } // VerifyIntegrity checks the integrity of the ciphertext message. -// The HMAC is calculated over the cipher state concatenated with the -// AES output, instead of being calculated over the confounder and -// plaintext. This allows the message receiver to verify the -// integrity of the message before decrypting the message. -// Therefore the pt value to this interface method is not use. Pass any []byte. +// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this +// interface method is not use. Pass any []byte. func (e Aes256CtsHmacSha384192) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool { // We don't need ib just there for the interface return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e) diff --git a/v8/crypto/common/common.go b/v8/crypto/common/common.go index 9db9541d..dab55be7 100644 --- a/v8/crypto/common/common.go +++ b/v8/crypto/common/common.go @@ -92,39 +92,28 @@ func GetIntegrityHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, e // VerifyChecksum compares the checksum of the msg bytes is the same as the checksum provided. func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool { - //The ciphertext output is the concatenation of the output of the basic - //encryption function E and a (possibly truncated) HMAC using the - //specified hash function H, both applied to the plaintext with a - //random confounder prefix and sufficient padding to bring it to a - //multiple of the message block size. When the HMAC is computed, the - //key is used in the protocol key form. + //The encrypted message is a concatenation of the encrypted output and the hash HMAC. expectedMAC, _ := GetChecksumHash(msg, key, usage, etype) return hmac.Equal(chksum, expectedMAC) } // GetUsageKc returns the checksum key usage value for the usage number un. // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Kc = DK(base-key, usage | 0x99); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKc(un uint32) []byte { return getUsage(un, 0x99) } // GetUsageKe returns the encryption key usage value for the usage number un // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Ke = DK(base-key, usage | 0xAA); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKe(un uint32) []byte { return getUsage(un, 0xAA) } // GetUsageKi returns the integrity key usage value for the usage number un // -// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. -// -// Ki = DK(base-key, usage | 0x55); +// See RFC 3961 5.3 key-derivation function definition. func GetUsageKi(un uint32) []byte { return getUsage(un, 0x55) } diff --git a/v8/crypto/des3-cbc-sha1-kd.go b/v8/crypto/des3-cbc-sha1-kd.go index c3edbbc8..6e650eb6 100644 --- a/v8/crypto/des3-cbc-sha1-kd.go +++ b/v8/crypto/des3-cbc-sha1-kd.go @@ -15,41 +15,6 @@ import ( //RFC: 3961 Section 6.3 -/* - des3-cbc-hmac-sha1-kd, hmac-sha1-des3-kd - ------------------------------------------------ - protocol key format 24 bytes, parity in low - bit of each - - key-generation seed 21 bytes - length - - hash function SHA-1 - - HMAC output size 160 bits - - message block size 8 bytes - - default string-to-key empty string - params - - encryption and triple-DES encrypt and - decryption functions decrypt, in outer-CBC - mode (cipher block size - 8 octets) - - key generation functions: - - random-to-key DES3random-to-key (see - below) - - string-to-key DES3string-to-key (see - below) - - The des3-cbc-hmac-sha1-kd encryption type is assigned the value - sixteen (16). The hmac-sha1-des3-kd checksum algorithm is assigned a - checksum type number of twelve (12)*/ - // Des3CbcSha1Kd implements Kerberos encryption type des3-cbc-hmac-sha1-kd type Des3CbcSha1Kd struct { } diff --git a/v8/crypto/etype/etype.go b/v8/crypto/etype/etype.go index ee7510e2..ab1496d3 100644 --- a/v8/crypto/etype/etype.go +++ b/v8/crypto/etype/etype.go @@ -8,20 +8,20 @@ type EType interface { GetETypeID() int32 GetHashID() int32 GetKeyByteSize() int - GetKeySeedBitLength() int // key-generation seed length, k - GetDefaultStringToKeyParams() string // default string-to-key parameters (s2kparams) - StringToKey(string, salt, s2kparams string) ([]byte, error) // string-to-key (UTF-8 string, UTF-8 string, opaque)->(protocol-key) - RandomToKey(b []byte) []byte // random-to-key (bitstring[K])->(protocol-key) - GetHMACBitLength() int // HMAC output size, h - GetMessageBlockByteSize() int // message block size, m - EncryptData(key, data []byte) ([]byte, []byte, error) // E function - encrypt (specific-key, state, octet string)->(state, octet string) + GetKeySeedBitLength() int + GetDefaultStringToKeyParams() string + StringToKey(string, salt, s2kparams string) ([]byte, error) + RandomToKey(b []byte) []byte + GetHMACBitLength() int + GetMessageBlockByteSize() int + EncryptData(key, data []byte) ([]byte, []byte, error) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) - DecryptData(key, data []byte) ([]byte, error) // D function + DecryptData(key, data []byte) ([]byte, error) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) - GetCypherBlockBitLength() int // cipher block size, c - GetConfounderByteSize() int // This is the same as the cipher block size but in bytes. - DeriveKey(protocolKey, usage []byte) ([]byte, error) // DK key-derivation (protocol-key, integer)->(specific-key) - DeriveRandom(protocolKey, usage []byte) ([]byte, error) // DR pseudo-random (protocol-key, octet-string)->(octet-string) + GetCypherBlockBitLength() int + GetConfounderByteSize() int + DeriveKey(protocolKey, usage []byte) ([]byte, error) + DeriveRandom(protocolKey, usage []byte) ([]byte, error) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool diff --git a/v8/crypto/rc4-hmac.go b/v8/crypto/rc4-hmac.go index 75cfabc9..42f84b85 100644 --- a/v8/crypto/rc4-hmac.go +++ b/v8/crypto/rc4-hmac.go @@ -14,9 +14,7 @@ import ( "golang.org/x/crypto/md4" ) -//http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java#ArcFourCrypto.encrypt%28byte%5B%5D%2Cint%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cint%2Cint%29 - -// RC4HMAC implements Kerberos encryption type aes256-cts-hmac-sha1-96 +// RC4HMAC implements Kerberos encryption type rc4-hmac type RC4HMAC struct { } diff --git a/v8/crypto/rfc3961/encryption.go b/v8/crypto/rfc3961/encryption.go index 3c4f412b..1383258c 100644 --- a/v8/crypto/rfc3961/encryption.go +++ b/v8/crypto/rfc3961/encryption.go @@ -112,12 +112,6 @@ func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([] // VerifyIntegrity verifies the integrity of cipertext bytes ct. func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool { - //The ciphertext output is the concatenation of the output of the basic - //encryption function E and a (possibly truncated) HMAC using the - //specified hash function H, both applied to the plaintext with a - //random confounder prefix and sufficient padding to bring it to a - //multiple of the message block size. When the HMAC is computed, the - //key is used in the protocol key form. h := make([]byte, etype.GetHMACBitLength()/8) copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:]) expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype) diff --git a/v8/crypto/rfc3961/keyDerivation.go b/v8/crypto/rfc3961/keyDerivation.go index 9e2927a0..ed9b169c 100644 --- a/v8/crypto/rfc3961/keyDerivation.go +++ b/v8/crypto/rfc3961/keyDerivation.go @@ -28,16 +28,7 @@ func DeriveRandom(key, usage []byte, e etype.EType) ([]byte, error) { nFoldUsage := Nfold(usage, n) //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8) out := make([]byte, k/8) - - /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary. - The construct is as follows (where | indicates concatenation): - - K1 = E(Key, n-fold(Constant), initial-cipher-state) - K2 = E(Key, K1, initial-cipher-state) - K3 = E(Key, K2, initial-cipher-state) - K4 = ... - - DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/ + // Keep feeding the output back into the encryption function until it is no longer short than k. _, K, err := e.EncryptData(key, nFoldUsage) if err != nil { return out, err diff --git a/v8/crypto/rfc3961/nfold.go b/v8/crypto/rfc3961/nfold.go index 779d1c6e..9536b1e3 100644 --- a/v8/crypto/rfc3961/nfold.go +++ b/v8/crypto/rfc3961/nfold.go @@ -1,27 +1,6 @@ package rfc3961 -/* -Implementation of the n-fold algorithm as defined in RFC 3961. - -n-fold is an algorithm that takes m input bits and "stretches" them -to form n output bits with equal contribution from each input bit to -the output, as described in [Blumenthal96]: - -We first define a primitive called n-folding, which takes a -variable-length input block and produces a fixed-length output -sequence. The intent is to give each input bit approximately -equal weight in determining the value of each output bit. Note -that whenever we need to treat a string of octets as a number, the -assumed representation is Big-Endian -- Most Significant Byte -first. - -To n-fold a number X, replicate the input value to a length that -is the least common multiple of n and the length of X. Before -each repetition, the input is rotated to the right by 13 bit -positions. The successive n-bit chunks are added together using -1's-complement addition (that is, with end-around carry) to yield -a n-bit result.... -*/ +// Implementation of the n-fold algorithm as defined in RFC 3961. /* Credits This golang implementation of nfold used the following project for help with implementation detail. diff --git a/v8/crypto/rfc3962/keyDerivation.go b/v8/crypto/rfc3962/keyDerivation.go index a2de3239..fb402d97 100644 --- a/v8/crypto/rfc3962/keyDerivation.go +++ b/v8/crypto/rfc3962/keyDerivation.go @@ -35,11 +35,9 @@ func StringToKeyIter(secret, salt string, iterations int64, e etype.EType) ([]by // S2KparamsToItertions converts the string representation of iterations to an integer func S2KparamsToItertions(s2kparams string) (int64, error) { - //process s2kparams string - //The parameter string is four octets indicating an unsigned - //number in big-endian order. This is the number of iterations to be - //performed. If the value is 00 00 00 00, the number of iterations to - //be performed is 4,294,967,296 (2**32). + //The s2kparams string should be hex string representing 4 bytes + //The 4 bytes represent a number in big endian order + //If the value is zero then the number of iterations should be 4,294,967,296 (2^32) var i uint32 if len(s2kparams) != 8 { return int64(s2kParamsZero), errors.New("invalid s2kparams length") @@ -49,10 +47,5 @@ func S2KparamsToItertions(s2kparams string) (int64, error) { return int64(s2kParamsZero), errors.New("invalid s2kparams, cannot decode string to bytes") } i = binary.BigEndian.Uint32(b) - //buf := bytes.NewBuffer(b) - //err = binary.Read(buf, binary.BigEndian, &i) - if err != nil { - return int64(s2kParamsZero), errors.New("invalid s2kparams, cannot convert to big endian int32") - } return int64(i), nil } diff --git a/v8/crypto/rfc4757/keyDerivation.go b/v8/crypto/rfc4757/keyDerivation.go index 5e7ec480..d1f90c07 100644 --- a/v8/crypto/rfc4757/keyDerivation.go +++ b/v8/crypto/rfc4757/keyDerivation.go @@ -33,21 +33,6 @@ func StringToKey(secret string) ([]byte, error) { } func deriveKeys(key, checksum []byte, usage uint32, export bool) (k1, k2, k3 []byte) { - //if export { - // L40 := make([]byte, 14, 14) - // copy(L40, []byte(`fortybits`)) - // k1 = HMAC(key, L40) - //} else { - // tb := MessageTypeBytes(usage) - // k1 = HMAC(key, tb) - //} - //k2 = k1[:16] - //if export { - // mask := []byte{0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB} - // copy(k1[7:16], mask) - //} - //k3 = HMAC(k1, checksum) - //return k1 = key k2 = HMAC(k1, UsageToMSMsgType(usage)) k3 = HMAC(k2, checksum) diff --git a/v8/crypto/rfc8009/encryption.go b/v8/crypto/rfc8009/encryption.go index bb6f9795..54cff7b4 100644 --- a/v8/crypto/rfc8009/encryption.go +++ b/v8/crypto/rfc8009/encryption.go @@ -108,11 +108,8 @@ func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte // GetIntegityHash returns a keyed integrity hash of the bytes provided as defined in RFC 8009 func GetIntegityHash(iv, c, key []byte, usage uint32, e etype.EType) ([]byte, error) { // Generate and append integrity hash - // The HMAC is calculated over the cipher state concatenated with the - // AES output, instead of being calculated over the confounder and - // plaintext. This allows the message receiver to verify the - // integrity of the message before decrypting the message. - // H = HMAC(Ki, IV | C) + // Rather than calculating the hash over the confounder and plaintext + // it is calculated over the iv concatenated with the AES cipher output. ib := append(iv, c...) return common.GetIntegrityHash(ib, key, usage, e) } diff --git a/v8/crypto/rfc8009/keyDerivation.go b/v8/crypto/rfc8009/keyDerivation.go index 2aeeda94..e9473222 100644 --- a/v8/crypto/rfc8009/keyDerivation.go +++ b/v8/crypto/rfc8009/keyDerivation.go @@ -24,16 +24,6 @@ func DeriveRandom(protocolKey, usage []byte, e etype.EType) ([]byte, error) { // DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods. // // https://tools.ietf.org/html/rfc8009#section-5 -// -// If the enctype is aes128-cts-hmac-sha256-128: -// Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 128) -// Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 128) -// Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 128) -// -// If the enctype is aes256-cts-hmac-sha384-192: -// Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 192) -// Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 256) -// Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 192) func DeriveKey(protocolKey, label []byte, e etype.EType) []byte { var context []byte var kl int diff --git a/v8/gssapi/MICToken.go b/v8/gssapi/MICToken.go index cb4ede11..ab8daa28 100644 --- a/v8/gssapi/MICToken.go +++ b/v8/gssapi/MICToken.go @@ -13,32 +13,7 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/* -From RFC 4121, section 4.2.6.1: - - Use of the GSS_GetMIC() call yields a token (referred as the MIC - token in this document), separate from the user data being protected, - which can be used to verify the integrity of that data as received. - The token has the following format: - - Octet no Name Description - -------------------------------------------------------------- - 0..1 TOK_ID Identification field. Tokens emitted by - GSS_GetMIC() contain the hex value 04 04 - expressed in big-endian order in this - field. - 2 Flags Attributes field, as described in section - 4.2.2. - 3..7 Filler Contains five octets of hex value FF. - 8..15 SND_SEQ Sequence number field in clear text, - expressed in big-endian order. - 16..last SGN_CKSUM Checksum of the "to-be-signed" data and - octet 0..15, as described in section 4.2.4. - - The Filler field is included in the checksum calculation for - simplicity. - -*/ +// RFC 4121, section 4.2.6.1 const ( // MICTokenFlagSentByAcceptor - this flag indicates the sender is the context acceptor. When not set, it indicates the sender is the context initiator @@ -106,9 +81,6 @@ func (mt *MICToken) SetChecksum(key types.EncryptionKey, keyUsage uint32) error } // Compute and return the checksum of this token, computed using the passed key and key usage. -// Confirms to RFC 4121 in that the checksum will be computed over { body | header }. -// In the context of Kerberos MIC tokens, mostly keyusage GSSAPI_ACCEPTOR_SIGN (=23) -// and GSSAPI_INITIATOR_SIGN (=25) will be used. // Note: This will NOT update the struct's Checksum field. func (mt *MICToken) checksum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) { if mt.Payload == nil { diff --git a/v8/gssapi/wrapToken.go b/v8/gssapi/wrapToken.go index 3d437467..c5211395 100644 --- a/v8/gssapi/wrapToken.go +++ b/v8/gssapi/wrapToken.go @@ -13,46 +13,8 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/* -From RFC 4121, section 4.2.6.2: - - Use of the GSS_Wrap() call yields a token (referred as the Wrap token - in this document), which consists of a descriptive header, followed - by a body portion that contains either the input user data in - plaintext concatenated with the checksum, or the input user data - encrypted. The GSS_Wrap() token SHALL have the following format: - - Octet no Name Description - -------------------------------------------------------------- - 0..1 TOK_ID Identification field. Tokens emitted by - GSS_Wrap() contain the hex value 05 04 - expressed in big-endian order in this - field. - 2 Flags Attributes field, as described in section - 4.2.2. - 3 Filler Contains the hex value FF. - 4..5 EC Contains the "extra count" field, in big- - endian order as described in section 4.2.3. - 6..7 RRC Contains the "right rotation count" in big- - endian order, as described in section - 4.2.5. - 8..15 SndSeqNum Sequence number field in clear text, - expressed in big-endian order. - 16..last Data Encrypted data for Wrap tokens with - confidentiality, or plaintext data followed - by the checksum for Wrap tokens without - confidentiality, as described in section - 4.2.4. - -Quick notes: - - "EC" or "Extra Count" refers to the length of the checksum. - - "Flags" (complete details in section 4.2.2) is a set of bits: - - if bit 0 is set, it means the token was sent by the acceptor (generally the kerberized service). - - bit 1 indicates that the token's payload is encrypted - - bit 2 indicates if the message is protected using a subkey defined by the acceptor. - - When computing checksums, EC and RRC MUST be set to 0. - - Wrap Tokens are not ASN.1 encoded. -*/ +// RFC 4121, section 4.2.6.2 + const ( HdrLen = 16 // Length of the Wrap Token's header FillerByte byte = 0xFF @@ -121,10 +83,6 @@ func (wt *WrapToken) SetCheckSum(key types.EncryptionKey, keyUsage uint32) error } // ComputeCheckSum computes and returns the checksum of this token, computed using the passed key and key usage. -// Conforms to RFC 4121 in that the checksum will be computed over { body | header }, -// with the EC and RRC flags zeroed out. -// In the context of Kerberos Wrap tokens, mostly keyusage GSSAPI_ACCEPTOR_SEAL (=22) -// and GSSAPI_INITIATOR_SEAL (=24) will be used. // Note: This will NOT update the struct's Checksum field. func (wt *WrapToken) computeCheckSum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) { if wt.Payload == nil { diff --git a/v8/keytab/keytab.go b/v8/keytab/keytab.go index faaaa051..dd75f7ff 100644 --- a/v8/keytab/keytab.go +++ b/v8/keytab/keytab.go @@ -163,12 +163,6 @@ func (kt *Keytab) Unmarshal(b []byte) error { if kt.version == 1 && isNativeEndianLittle() { endian = binary.LittleEndian } - /* - After the two-byte version indicator, the file contains a sequence of signed 32-bit record lengths followed by key records or holes. - A positive record length indicates a valid key entry whose size is equal to or less than the record length. - A negative length indicates a zero-filled hole whose size is the inverse of the length. - A length of 0 indicates the end of the file. - */ // n tracks position in the byte array n := 2 l, err := readInt32(b, &n, &endian) @@ -181,7 +175,6 @@ func (kt *Keytab) Unmarshal(b []byte) error { l = l * -1 n = n + int(l) } else { - //fmt.Printf("Bytes for entry: %v\n", b[n:n+int(l)]) if n < 0 { return fmt.Errorf("%d can't be less than zero", n) } @@ -218,9 +211,9 @@ func (kt *Keytab) Unmarshal(b []byte) error { if err != nil { return err } - //The 32-bit key version overrides the 8-bit key version. - // To determine if it is present, the implementation must check that at least 4 bytes remain in the record after the other fields are read, - // and that the value of the 32-bit integer contained in those bytes is non-zero. + // The 32-bit key version overrides the 8-bit key version. + // If at least 4 bytes are left after the other fields are read and they are non-zero + // this indicates the 32-bit version is present. if len(eb)-p >= 4 { // The 32-bit key may be present ri32, err := readInt32(eb, &p, &endian) diff --git a/v8/messages/APRep.go b/v8/messages/APRep.go index bbbb343f..555fb807 100644 --- a/v8/messages/APRep.go +++ b/v8/messages/APRep.go @@ -11,21 +11,6 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/* -AP-REP ::= [APPLICATION 15] SEQUENCE { -pvno [0] INTEGER (5), -msg-type [1] INTEGER (15), -enc-part [2] EncryptedData -- EncAPRepPart -} - -EncAPRepPart ::= [APPLICATION 27] SEQUENCE { - ctime [0] KerberosTime, - cusec [1] Microseconds, - subkey [2] EncryptionKey OPTIONAL, - seq-number [3] UInt32 OPTIONAL -} -*/ - // APRep implements RFC 4120 KRB_AP_REP: https://tools.ietf.org/html/rfc4120#section-5.5.2. type APRep struct { PVNO int `asn1:"explicit,tag:0"` diff --git a/v8/messages/APReq.go b/v8/messages/APReq.go index 5c3d4443..18360797 100644 --- a/v8/messages/APReq.go +++ b/v8/messages/APReq.go @@ -17,19 +17,6 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/*AP-REQ ::= [APPLICATION 14] SEQUENCE { -pvno [0] INTEGER (5), -msg-type [1] INTEGER (14), -ap-options [2] APOptions, -ticket [3] Ticket, -authenticator [4] EncryptedData -- Authenticator -} - -APOptions ::= KerberosFlags --- reserved(0), --- use-session-key(1), --- mutual-required(2)*/ - type marshalAPReq struct { PVNO int `asn1:"explicit,tag:0"` MsgType int `asn1:"explicit,tag:1"` @@ -157,22 +144,11 @@ func (a *APReq) Verify(kt *keytab.Keytab, d time.Duration, cAddr types.HostAddre // Decrypt ticket's encrypted part with service key //TODO decrypt with service's session key from its TGT is use-to-user. Need to figure out how to get TGT. //if types.IsFlagSet(&a.APOptions, flags.APOptionUseSessionKey) { - // //If the USE-SESSION-KEY flag is set in the ap-options field, it indicates to - // //the server that user-to-user authentication is in use, and that the ticket - // //is encrypted in the session key from the server's TGT rather than in the server's secret key. // err := a.Ticket.Decrypt(tgt.DecryptedEncPart.Key) // if err != nil { // return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of ticket provided using session key") // } //} else { - // // Because it is possible for the server to be registered in multiple - // // realms, with different keys in each, the srealm field in the - // // unencrypted portion of the ticket in the KRB_AP_REQ is used to - // // specify which secret key the server should use to decrypt that - // // ticket.The KRB_AP_ERR_NOKEY error code is returned if the server - // // doesn't have the proper key to decipher the ticket. - // // The ticket is decrypted using the version of the server's key - // // specified by the ticket. // err := a.Ticket.DecryptEncPart(*kt, &a.Ticket.SName) // if err != nil { // return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of service ticket provided") @@ -195,9 +171,8 @@ func (a *APReq) Verify(kt *keytab.Keytab, d time.Duration, cAddr types.HostAddre // Check client's address is listed in the client addresses in the ticket if len(a.Ticket.DecryptedEncPart.CAddr) > 0 { - //The addresses in the ticket (if any) are then searched for an address matching the operating-system reported - //address of the client. If no match is found or the server insists on ticket addresses but none are present in - //the ticket, the KRB_AP_ERR_BADADDR error is returned. + //If client addresses are present check if any of them match the source IP that sent the APReq + //If there is no match return KRB_AP_ERR_BADADDR error. if !types.HostAddressesContains(a.Ticket.DecryptedEncPart.CAddr, cAddr) { return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "client address not within the list contained in the service ticket") } diff --git a/v8/messages/KDCRep.go b/v8/messages/KDCRep.go index eed48246..41d2b2ca 100644 --- a/v8/messages/KDCRep.go +++ b/v8/messages/KDCRep.go @@ -135,12 +135,8 @@ func (e *EncKDCRepPart) Unmarshal(b []byte) error { _, err := asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncASRepPart)) if err != nil { // Try using tag 26 - /* Ref: RFC 4120 - Compatibility note: Some implementations unconditionally send an - encrypted EncTGSRepPart (application tag number 26) in this field - regardless of whether the reply is a AS-REP or a TGS-REP. In the - interest of compatibility, implementors MAY relax the check on the - tag number of the decrypted ENC-PART.*/ + // Ref: RFC 4120 - mentions that some implementations use application tag number 26 wether or not the reply is + // a AS-REP or a TGS-REP. _, err = asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncTGSRepPart)) if err != nil { return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part within KDC_REP") diff --git a/v8/messages/KRBSafe.go b/v8/messages/KRBSafe.go index d378942f..52cd2844 100644 --- a/v8/messages/KRBSafe.go +++ b/v8/messages/KRBSafe.go @@ -11,24 +11,6 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/* -KRB-SAFE ::= [APPLICATION 20] SEQUENCE { - pvno [0] INTEGER (5), - msg-type [1] INTEGER (20), - safe-body [2] KRB-SAFE-BODY, - cksum [3] Checksum -} - -KRB-SAFE-BODY ::= SEQUENCE { - user-data [0] OCTET STRING, - timestamp [1] KerberosTime OPTIONAL, - usec [2] Microseconds OPTIONAL, - seq-number [3] UInt32 OPTIONAL, - s-address [4] HostAddress, - r-address [5] HostAddress OPTIONAL -} -*/ - // KRBSafe implements RFC 4120 KRB_SAFE: https://tools.ietf.org/html/rfc4120#section-5.6.1. type KRBSafe struct { PVNO int `asn1:"explicit,tag:0"` diff --git a/v8/pac/credentials_info.go b/v8/pac/credentials_info.go index 152df613..2266ce8f 100644 --- a/v8/pac/credentials_info.go +++ b/v8/pac/credentials_info.go @@ -66,10 +66,6 @@ func (c *CredentialsInfo) DecryptEncPart(k types.EncryptionKey) error { } // CredentialData implements https://msdn.microsoft.com/en-us/library/cc237952.aspx -// This structure is encrypted prior to being encoded in any other structures. -// Encryption is performed by first serializing the data structure via Network Data Representation (NDR) encoding, as specified in [MS-RPCE]. -// Once serialized, the data is encrypted using the key and cryptographic system selected through the AS protocol and the KRB_AS_REP message -// Fields (for capturing this information) and cryptographic parameters are specified in PAC_CREDENTIAL_INFO (section 2.6.1). type CredentialData struct { CredentialCount uint32 Credentials []SECPKGSupplementalCred // Size is the value of CredentialCount diff --git a/v8/pac/kerb_validation_info.go b/v8/pac/kerb_validation_info.go index 601d154e..dde78614 100644 --- a/v8/pac/kerb_validation_info.go +++ b/v8/pac/kerb_validation_info.go @@ -26,11 +26,6 @@ const ( ) // KerbValidationInfo implement https://msdn.microsoft.com/en-us/library/cc237948.aspx -// The KERB_VALIDATION_INFO structure defines the user's logon and authorization information -// provided by the DC. The KERB_VALIDATION_INFO structure is a subset of the -// NETLOGON_VALIDATION_SAM_INFO4 structure ([MS-NRPC] section 2.2.1.4.13). -// It is a subset due to historical reasons and to the use of the common Active Directory to generate this information. -// The KERB_VALIDATION_INFO structure is marshaled by RPC [MS-RPCE]. type KerbValidationInfo struct { LogOnTime mstypes.FileTime LogOffTime mstypes.FileTime diff --git a/v8/pac/signature_data.go b/v8/pac/signature_data.go index 3f4b2b39..8f6aa58f 100644 --- a/v8/pac/signature_data.go +++ b/v8/pac/signature_data.go @@ -14,21 +14,9 @@ The Key Usage Value MUST be KERB_NON_KERB_CKSUM_SALT (17) [MS-KILE] (section 3.1 Server Signature (SignatureType = 0x00000006) https://msdn.microsoft.com/en-us/library/cc237957.aspx -The KDC will use the long-term key that the KDC shares with the server, so that the server can verify this signature on receiving a PAC. -The server signature is a keyed hash [RFC4757] of the entire PAC message, with the Signature fields of both PAC_SIGNATURE_DATA structures set to zero. -The key used to protect the ciphertext part of the response is used. -The checksum type corresponds to the key unless the key is DES, in which case the KERB_CHECKSUM_HMAC_MD5 key is used. -The resulting hash value is then placed in the Signature field of the server's PAC_SIGNATURE_DATA structure. KDC Signature (SignatureType = 0x00000007) https://msdn.microsoft.com/en-us/library/dd357117.aspx -The KDC will use KDC (krbtgt) key [RFC4120], so that other KDCs can verify this signature on receiving a PAC. -The KDC signature is a keyed hash [RFC4757] of the Server Signature field in the PAC message. -The cryptographic system that is used to calculate the checksum depends on which system the KDC supports, as defined below: -- Supports RC4-HMAC --> KERB_CHECKSUM_HMAC_MD5 -- Does not support RC4-HMAC and supports AES256 --> HMAC_SHA1_96_AES256 -- Does not support RC4-HMAC or AES256-CTS-HMAC-SHA1-96, and supports AES128-CTS-HMAC-SHA1-96 --> HMAC_SHA1_96_AES128 -- Does not support RC4-HMAC, AES128-CTS-HMAC-SHA1-96 or AES256-CTS-HMAC-SHA1-96 --> None. The checksum operation will fail. */ // SignatureData implements https://msdn.microsoft.com/en-us/library/cc237955.aspx diff --git a/v8/pac/supplemental_cred.go b/v8/pac/supplemental_cred.go index ae131755..d40679d4 100644 --- a/v8/pac/supplemental_cred.go +++ b/v8/pac/supplemental_cred.go @@ -70,9 +70,6 @@ func isFlagSet(f uint32, i uint32) bool { } // SECPKGSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237956.aspx -// The SECPKG_SUPPLEMENTAL_CRED structure defines the name of the security package that requires -// supplemental credentials and the credential buffer for that package. -// The SECPKG_SUPPLEMENTAL_CRED structure is marshaled by RPC. type SECPKGSupplementalCred struct { PackageName mstypes.RPCUnicodeString CredentialSize uint32 diff --git a/v8/service/cache.go b/v8/service/cache.go index 8201ea47..038e594e 100644 --- a/v8/service/cache.go +++ b/v8/service/cache.go @@ -7,27 +7,7 @@ import ( "time" ) -/*The server MUST utilize a replay cache to remember any authenticator -presented within the allowable clock skew. -The replay cache will store at least the server name, along with the -client name, time, and microsecond fields from the recently-seen -authenticators, and if a matching tuple is found, the -KRB_AP_ERR_REPEAT error is returned. Note that the rejection here is -restricted to authenticators from the same principal to the same -server. Other client principals communicating with the same server -principal should not have their authenticators rejected if the time -and microsecond fields happen to match some other client's -authenticator. - -If a server loses track of authenticators presented within the -allowable clock skew, it MUST reject all requests until the clock -skew interval has passed, providing assurance that any lost or -replayed authenticators will fall outside the allowable clock skew -and can no longer be successfully replayed. If this were not done, -an attacker could subvert the authentication by recording the ticket -and authenticator sent over the network to a server and replaying -them following an event that caused the server to lose track of -recently seen authenticators.*/ +// Replay cache is required as specified in RFC 4120 section 3.2.3 // Cache for tickets received from clients keyed by fully qualified client name. Used to track replay of tickets. type Cache struct { diff --git a/v8/spnego/krb5Token.go b/v8/spnego/krb5Token.go index 39ba1adc..43f8a82c 100644 --- a/v8/spnego/krb5Token.go +++ b/v8/spnego/krb5Token.go @@ -216,26 +216,3 @@ func newAuthenticatorChksum(flags []int) []byte { } return a } - -/* -The authenticator checksum field SHALL have the following format: - -Octet Name Description ------------------------------------------------------------------ -0..3 Lgth Number of octets in Bnd field; Represented - in little-endian order; Currently contains - hex value 10 00 00 00 (16). -4..19 Bnd Channel binding information, as described in - section 4.1.1.2. -20..23 Flags Four-octet context-establishment flags in - little-endian order as described in section - 4.1.1.1. -24..25 DlgOpt The delegation option identifier (=1) in - little-endian order [optional]. This field - and the next two fields are present if and - only if GSS_C_DELEG_FLAG is set as described - in section 4.1.1.1. -26..27 Dlgth The length of the Deleg field in little-endian order [optional]. -28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional]. -n..last Exts Extensions [optional]. -*/ diff --git a/v8/spnego/negotiationToken.go b/v8/spnego/negotiationToken.go index c8b99d95..409ffcf9 100644 --- a/v8/spnego/negotiationToken.go +++ b/v8/spnego/negotiationToken.go @@ -13,39 +13,7 @@ import ( "github.com/jcmturner/gokrb5/v8/types" ) -/* -https://msdn.microsoft.com/en-us/library/ms995330.aspx - -NegotiationToken ::= CHOICE { - negTokenInit [0] NegTokenInit, This is the Negotiation token sent from the client to the server. - negTokenResp [1] NegTokenResp -} - -NegTokenInit ::= SEQUENCE { - mechTypes [0] MechTypeList, - reqFlags [1] ContextFlags OPTIONAL, - -- inherited from RFC 2478 for backward compatibility, - -- RECOMMENDED to be left out - mechToken [2] OCTET STRING OPTIONAL, - mechListMIC [3] OCTET STRING OPTIONAL, - ... -} - -NegTokenResp ::= SEQUENCE { - negState [0] ENUMERATED { - accept-completed (0), - accept-incomplete (1), - reject (2), - request-mic (3) - } OPTIONAL, - -- REQUIRED in the first reply from the target - supportedMech [1] MechType OPTIONAL, - -- present only in the first reply from the target - responseToken [2] OCTET STRING OPTIONAL, - mechListMIC [3] OCTET STRING OPTIONAL, - ... -} -*/ +// https://msdn.microsoft.com/en-us/library/ms995330.aspx // Negotiation state values. const ( diff --git a/v8/types/Authenticator.go b/v8/types/Authenticator.go index 5251509c..1fdba78a 100644 --- a/v8/types/Authenticator.go +++ b/v8/types/Authenticator.go @@ -14,27 +14,8 @@ import ( "github.com/jcmturner/gokrb5/v8/iana/asnAppTag" ) -/*Authenticator ::= [APPLICATION 2] SEQUENCE { -authenticator-vno [0] INTEGER (5), -crealm [1] Realm, -cname [2] PrincipalName, -cksum [3] Checksum OPTIONAL, -cusec [4] Microseconds, -ctime [5] KerberosTime, -subkey [6] EncryptionKey OPTIONAL, -seq-number [7] UInt32 OPTIONAL, -authorization-data [8] AuthorizationData OPTIONAL -} - - cksum - This field contains a checksum of the application data that - accompanies the KRB_AP_REQ, computed using a key usage value of 10 - in normal application exchanges, or 6 when used in the TGS-REQ - PA-TGS-REQ AP-DATA field. - -*/ - -// Authenticator - A record containing information that can be shown to have been recently generated using the session key known only by the client and server. +// Authenticator - A record containing information that can be shown to have been recently generated using the session +// key known only by the client and server. // https://tools.ietf.org/html/rfc4120#section-5.5.1 type Authenticator struct { AVNO int `asn1:"explicit,tag:0"` diff --git a/v8/types/AuthorizationData.go b/v8/types/AuthorizationData.go index c9448008..80c477ce 100644 --- a/v8/types/AuthorizationData.go +++ b/v8/types/AuthorizationData.go @@ -7,74 +7,6 @@ import ( // Reference: https://www.ietf.org/rfc/rfc4120.txt // Section: 5.2.6 -/* -AuthorizationData - --- NOTE: AuthorizationData is always used as an OPTIONAL field and --- should not be empty. -AuthorizationData ::= SEQUENCE OF SEQUENCE { -ad-type [0] Int32, -ad-data [1] OCTET STRING -} - -ad-data -This field contains authorization data to be interpreted according -to the value of the corresponding ad-type field. - -ad-type - This field specifies the format for the ad-data subfield. All -negative values are reserved for local use. Non-negative values -are reserved for registered use. - -Each sequence of type and data is referred to as an authorization -element. Elements MAY be application specific; however, there is a -common set of recursive elements that should be understood by all -implementations. These elements contain other elements embedded -within them, and the interpretation of the encapsulating element -determines which of the embedded elements must be interpreted, and -which may be ignored. - -These common authorization data elements are recursively defined, -meaning that the ad-data for these types will itself contain a -sequence of authorization data whose interpretation is affected by -the encapsulating element. Depending on the meaning of the -encapsulating element, the encapsulated elements may be ignored, -might be interpreted as issued directly by the KDC, or might be -stored in a separate plaintext part of the ticket. The types of the -encapsulating elements are specified as part of the Kerberos -specification because the behavior based on these values should be -understood across implementations, whereas other elements need only -be understood by the applications that they affect. - -Authorization data elements are considered critical if present in a -ticket or authenticator. If an unknown authorization data element -type is received by a server either in an AP-REQ or in a ticket -contained in an AP-REQ, then, unless it is encapsulated in a known -authorization data element amending the criticality of the elements -it contains, authentication MUST fail. Authorization data is -intended to restrict the use of a ticket. If the service cannot -determine whether the restriction applies to that service, then a -security weakness may result if the ticket can be used for that -service. Authorization elements that are optional can be enclosed in -an AD-IF-RELEVANT element. - -In the definitions that follow, the value of the ad-type for the -element will be specified as the least significant part of the -subsection number, and the value of the ad-data will be as shown in -the ASN.1 structure that follows the subsection heading. - - Contents of ad-data ad-type - - DER encoding of AD-IF-RELEVANT 1 - - DER encoding of AD-KDCIssued 4 - - DER encoding of AD-AND-OR 5 - - DER encoding of AD-MANDATORY-FOR-KDC 8 - -*/ - // AuthorizationData implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.6 type AuthorizationData []AuthorizationDataEntry diff --git a/v8/types/HostAddress.go b/v8/types/HostAddress.go index b07593e8..895fe805 100644 --- a/v8/types/HostAddress.go +++ b/v8/types/HostAddress.go @@ -12,30 +12,6 @@ import ( "github.com/jcmturner/gokrb5/v8/iana/addrtype" ) -/* -HostAddress and HostAddresses - -HostAddress ::= SEQUENCE { - addr-type [0] Int32, - address [1] OCTET STRING -} - --- NOTE: HostAddresses is always used as an OPTIONAL field and --- should not be empty. -HostAddresses -- NOTE: subtly different from rfc1510, - -- but has a value mapping and encodes the same - ::= SEQUENCE OF HostAddress - -The host address encodings consist of two fields: - -addr-type - This field specifies the type of address that follows. Pre- - defined values for this field are specified in Section 7.5.3. - -address - This field encodes a single address of type addr-type. -*/ - // HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5 type HostAddresses []HostAddress diff --git a/v8/types/KerberosFlags.go b/v8/types/KerberosFlags.go index bd75d5b5..0f203834 100644 --- a/v8/types/KerberosFlags.go +++ b/v8/types/KerberosFlags.go @@ -7,62 +7,6 @@ import ( "github.com/jcmturner/gofork/encoding/asn1" ) -/* -KerberosFlags - -For several message types, a specific constrained bit string type, -KerberosFlags, is used. - -KerberosFlags ::= BIT STRING (SIZE (32..MAX)) --- minimum number of bits shall be sent, --- but no fewer than 32 - -Compatibility note: The following paragraphs describe a change from -the RFC 1510 description of bit strings that would result in -incompatility in the case of an implementation that strictly -conformed to ASN.1 DER and RFC 1510. - -ASN.1 bit strings have multiple uses. The simplest use of a bit -string is to contain a vector of bits, with no particular meaning -attached to individual bits. This vector of bits is not necessarily -a multiple of eight bits long. The use in Kerberos of a bit string -as a compact boolean vector wherein each element has a distinct -meaning poses some problems. The natural notation for a compact -boolean vector is the ASN.1 "NamedBit" notation, and the DER require -that encodings of a bit string using "NamedBit" notation exclude any -trailing zero bits. This truncation is easy to neglect, especially -given C language implementations that naturally choose to store -boolean vectors as 32-bit integers. - -For example, if the notation for KDCOptions were to include the -"NamedBit" notation, as in RFC 1510, and a KDCOptions value to be -encoded had only the "forwardable" (bit number one) bit set, the DER -encoding MUST include only two bits: the first reserved bit -("reserved", bit number zero, value zero) and the one-valued bit (bit -number one) for "forwardable". - -Most existing implementations of Kerberos unconditionally send 32 -bits on the wire when encoding bit strings used as boolean vectors. -This behavior violates the ASN.1 syntax used for flag values in RFC -1510, but it occurs on such a widely installed base that the protocol -description is being modified to accommodate it. - -Consequently, this document removes the "NamedBit" notations for -individual bits, relegating them to comments. The size constraint on -the KerberosFlags type requires that at least 32 bits be encoded at -all times, though a lenient implementation MAY choose to accept fewer -than 32 bits and to treat the missing bits as set to zero. - -Currently, no uses of KerberosFlags specify more than 32 bits' worth -of flags, although future revisions of this document may do so. When -more than 32 bits are to be transmitted in a KerberosFlags value, -future revisions to this document will likely specify that the -smallest number of bits needed to encode the highest-numbered one- -valued bit should be sent. This is somewhat similar to the DER -encoding of a bit string that is declared with the "NamedBit" -notation. -*/ - // NewKrbFlags returns an ASN1 BitString struct of the right size for KrbFlags. func NewKrbFlags() asn1.BitString { f := asn1.BitString{}