Skip to content

Commit 5b5e67f

Browse files
committed
Add support for creation / marshaling / enccryption of AP-REP messages
Fixes #432
1 parent 663478b commit 5b5e67f

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

v8/messages/APRep.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import (
55
"time"
66

77
"github.com/jcmturner/gofork/encoding/asn1"
8+
"github.com/jcmturner/gokrb5/v8/asn1tools"
9+
"github.com/jcmturner/gokrb5/v8/crypto"
10+
"github.com/jcmturner/gokrb5/v8/iana"
811
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
12+
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
913
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
1014
"github.com/jcmturner/gokrb5/v8/krberror"
1115
"github.com/jcmturner/gokrb5/v8/types"
@@ -47,3 +51,77 @@ func (a *EncAPRepPart) Unmarshal(b []byte) error {
4751
}
4852
return nil
4953
}
54+
55+
// Marshal the AP-REP message to a byte slice
56+
func (a *APRep) Marshal() (b []byte, err error) {
57+
b, err = asn1.Marshal(*a)
58+
if err != nil {
59+
return
60+
}
61+
62+
b = asn1tools.AddASNAppTag(b, asnAppTag.APREP)
63+
return
64+
}
65+
66+
// Decrypt the encrypted part of the APRep message
67+
func (a *APRep) DecryptEncPart(sessionKey types.EncryptionKey) (encpart EncAPRepPart, err error) {
68+
decrypted, err := crypto.DecryptEncPart(a.EncPart, sessionKey, uint32(keyusage.AP_REP_ENCPART))
69+
if err != nil {
70+
err = krberror.Errorf(err, krberror.DecryptingError, "error decrypting AP-REP enc-part")
71+
return
72+
}
73+
74+
err = encpart.Unmarshal(decrypted)
75+
if err != nil {
76+
err = krberror.Errorf(err, krberror.EncodingError, "error unmarshalling decrypted AP-REP enc-part")
77+
return
78+
}
79+
80+
return
81+
}
82+
83+
// Marshal the encrypted part of the APRep message to a byte slice
84+
func (a *EncAPRepPart) Marshal() (b []byte, err error) {
85+
b, err = asn1.Marshal(*a)
86+
if err != nil {
87+
return
88+
}
89+
90+
b = asn1tools.AddASNAppTag(b, asnAppTag.EncAPRepPart)
91+
return
92+
}
93+
94+
// Create a new APRep message with an encrypted enc-part
95+
func NewAPRep(tkt Ticket, sessionKey types.EncryptionKey, encPart EncAPRepPart) (a APRep, err error) {
96+
m, err := encPart.Marshal()
97+
if err != nil {
98+
err = krberror.Errorf(err, krberror.EncodingError, "marshaling error of AP-REP enc-part")
99+
return
100+
}
101+
102+
ed, err := crypto.GetEncryptedData(m, sessionKey, uint32(keyusage.AP_REP_ENCPART), tkt.EncPart.KVNO)
103+
if err != nil {
104+
err = krberror.Errorf(err, krberror.EncryptingError, "error encrypting AP-REP enc-part")
105+
return
106+
}
107+
108+
a = APRep{
109+
PVNO: iana.PVNO,
110+
MsgType: msgtype.KRB_AP_REP,
111+
EncPart: ed,
112+
}
113+
return
114+
}
115+
116+
// Verify a decrypted APRep enc-part against an authenticator. The authenticatror should be
117+
// same as the one embedded in the APReq message that casused this APRep to be generated
118+
func (a *EncAPRepPart) Verify(auth types.Authenticator) error {
119+
// check the response has the same time values as the request
120+
// Note - we can't use time.Equal() as m.clientCTime has a monotomic clock value and
121+
// which causes the equality to fail
122+
if !(a.CTime.Unix() == auth.CTime.Unix() && a.Cusec == auth.Cusec) {
123+
return fmt.Errorf("ap-rep time stamp does not match authenticator")
124+
}
125+
126+
return nil
127+
}

v8/messages/APRep_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,47 @@ import (
88
"github.com/jcmturner/gokrb5/v8/iana"
99
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
1010
"github.com/jcmturner/gokrb5/v8/test/testdata"
11+
"github.com/jcmturner/gokrb5/v8/types"
1112
"github.com/stretchr/testify/assert"
1213
)
1314

15+
// Sample data from MIT Kerberos v1.19.1
16+
17+
// from src/tests/asn.1/ktest.h
18+
const (
19+
SAMPLE_USEC = 123456
20+
SAMPLE_SEQ_NUMBER = 17
21+
SAMPLE_NONCE = 42
22+
SAMPLE_FLAGS = 0xFEDCBA98
23+
SAMPLE_ERROR = 0x3C
24+
)
25+
26+
func ktest_make_sample_ap_rep_enc_part() *EncAPRepPart {
27+
tm, _ := time.Parse(testdata.TEST_TIME_FORMAT, testdata.TEST_TIME)
28+
return &EncAPRepPart{
29+
CTime: tm,
30+
Cusec: SAMPLE_USEC,
31+
Subkey: *ktest_make_sample_keyblock(),
32+
SequenceNumber: SAMPLE_SEQ_NUMBER,
33+
}
34+
}
35+
36+
func ktest_make_sample_keyblock() *types.EncryptionKey {
37+
kv := []byte("12345678")
38+
return &types.EncryptionKey{
39+
KeyType: 1,
40+
KeyValue: kv,
41+
}
42+
}
43+
44+
func ktest_make_sample_enc_data() *types.EncryptedData {
45+
return &types.EncryptedData{
46+
EType: 0,
47+
KVNO: 5,
48+
Cipher: []byte("krbASN.1 test message"),
49+
}
50+
}
51+
1452
func TestUnmarshalAPRep(t *testing.T) {
1553
t.Parallel()
1654
var a APRep
@@ -67,3 +105,50 @@ func TestUnmarshalEncAPRepPart_optionalsNULL(t *testing.T) {
67105
assert.Equal(t, tt, a.CTime, "CTime not as expected")
68106
assert.Equal(t, 123456, a.Cusec, "Client microseconds not as expected")
69107
}
108+
109+
// test with all fields populated
110+
func TestAPRepEncPartMarshall(t *testing.T) {
111+
t.Parallel()
112+
113+
want, err := hex.DecodeString(testdata.MarshaledKRB5ap_rep_enc_part)
114+
assert.Nil(t, err, "error not expected decoding test data")
115+
116+
encpart := ktest_make_sample_ap_rep_enc_part()
117+
118+
b, err := encpart.Marshal()
119+
assert.Nil(t, err, "enc part marshal error not expected")
120+
assert.Equal(t, want, b)
121+
}
122+
123+
// test with the optionals not present
124+
func TestAPRepEncPartMarshall_optionalsNULL(t *testing.T) {
125+
t.Parallel()
126+
127+
want, err := hex.DecodeString(testdata.MarshaledKRB5ap_rep_enc_partOptionalsNULL)
128+
assert.Nil(t, err, "error not expected decoding test data")
129+
130+
encpart := ktest_make_sample_ap_rep_enc_part()
131+
encpart.SequenceNumber = 0
132+
encpart.Subkey = types.EncryptionKey{}
133+
134+
b, err := encpart.Marshal()
135+
assert.Nil(t, err, "enc part marshal error not expected")
136+
assert.Equal(t, want, b)
137+
}
138+
139+
func TestAprepMarshal(t *testing.T) {
140+
t.Parallel()
141+
142+
want, err := hex.DecodeString(testdata.MarshaledKRB5ap_rep)
143+
assert.Nil(t, err, "error not expected decoding test data")
144+
145+
aprep := APRep{
146+
PVNO: iana.PVNO,
147+
MsgType: msgtype.KRB_AP_REP,
148+
EncPart: *ktest_make_sample_enc_data(),
149+
}
150+
151+
b, err := aprep.Marshal()
152+
assert.Nil(t, err, "enc part marshal error not expected")
153+
assert.Equal(t, want, b)
154+
}

0 commit comments

Comments
 (0)