github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/apps/roughtime/agl_roughtime/protocol/protocol.go (about) 1 // Copyright 2016 The Roughtime Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. */ 14 15 // Package protocol implements the core of the Roughtime protocol. 16 package protocol 17 18 import ( 19 "bytes" 20 "crypto/sha512" 21 "encoding/binary" 22 "errors" 23 "io" 24 "math" 25 "sort" 26 27 "golang.org/x/crypto/ed25519" 28 ) 29 30 const ( 31 // NonceSize is the number of bytes in a nonce. 32 NonceSize = sha512.Size 33 // MinRequestSize is the minimum number of bytes in a request. 34 MinRequestSize = 1024 35 36 certificateContext = "RoughTime v1 delegation signature--\x00" 37 signedResponseContext = "RoughTime v1 response signature\x00" 38 ) 39 40 // makeTag converts a four character string into a Roughtime tag value. 41 func makeTag(tag string) uint32 { 42 if len(tag) != 4 { 43 panic("makeTag: len(tag) != 4: " + tag) 44 } 45 46 return uint32(tag[0]) | uint32(tag[1])<<8 | uint32(tag[2])<<16 | uint32(tag[3])<<24 47 } 48 49 var ( 50 // Various tags used in the Roughtime protocol. 51 tagCERT = makeTag("CERT") 52 tagDELE = makeTag("DELE") 53 tagINDX = makeTag("INDX") 54 tagMAXT = makeTag("MAXT") 55 tagMIDP = makeTag("MIDP") 56 tagMINT = makeTag("MINT") 57 tagNONC = makeTag("NONC") 58 tagPAD = makeTag("PAD\xff") 59 tagPATH = makeTag("PATH") 60 tagPUBK = makeTag("PUBK") 61 tagRADI = makeTag("RADI") 62 tagROOT = makeTag("ROOT") 63 tagSIG = makeTag("SIG\x00") 64 tagSREP = makeTag("SREP") 65 66 // TagNonce names the bytestring containing the client's nonce. 67 TagNonce = tagNONC 68 ) 69 70 // tagsSlice is the type of an array of tags. It provides utility functions so 71 // that they can be sorted. 72 type tagsSlice []uint32 73 74 func (t tagsSlice) Len() int { return len(t) } 75 func (t tagsSlice) Less(i, j int) bool { return t[i] < t[j] } 76 func (t tagsSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] } 77 78 // Encode converts a map of tags to bytestrings into an encoded message. The 79 // number of elements in msg and the sum of the lengths of all the bytestrings 80 // must be ≤ 2**32. 81 func Encode(msg map[uint32][]byte) ([]byte, error) { 82 if len(msg) == 0 { 83 return make([]byte, 4), nil 84 } 85 86 if len(msg) >= math.MaxInt32 { 87 return nil, errors.New("encode: too many tags") 88 } 89 90 var payloadSum uint64 91 for _, payload := range msg { 92 if len(payload) % 4 != 0 { 93 return nil, errors.New("encode: length of value is not a multiple of four") 94 } 95 payloadSum += uint64(len(payload)) 96 } 97 if payloadSum >= 1<<32 { 98 return nil, errors.New("encode: payloads too large") 99 } 100 101 tags := tagsSlice(make([]uint32, 0, len(msg))) 102 for tag := range msg { 103 tags = append(tags, tag) 104 } 105 sort.Sort(tags) 106 107 numTags := uint64(len(tags)) 108 109 encoded := make([]byte, 4*(1+numTags-1+numTags)+payloadSum) 110 binary.LittleEndian.PutUint32(encoded, uint32(len(tags))) 111 offsets := encoded[4:] 112 tagBytes := encoded[4*(1+(numTags-1)):] 113 payloads := encoded[4*(1+(numTags-1)+numTags):] 114 115 currentOffset := uint32(0) 116 117 for i, tag := range tags { 118 payload := msg[tag] 119 if i > 0 { 120 binary.LittleEndian.PutUint32(offsets, currentOffset) 121 offsets = offsets[4:] 122 } 123 124 binary.LittleEndian.PutUint32(tagBytes, tag) 125 tagBytes = tagBytes[4:] 126 127 if len(payload) > 0 { 128 copy(payloads, payload) 129 payloads = payloads[len(payload):] 130 currentOffset += uint32(len(payload)) 131 } 132 } 133 134 return encoded, nil 135 } 136 137 // Decode parses the output of encode back into a map of tags to bytestrings. 138 func Decode(bytes []byte) (map[uint32][]byte, error) { 139 if len(bytes) < 4 { 140 return nil, errors.New("decode: message too short to be valid") 141 } 142 if len(bytes) % 4 != 0 { 143 return nil, errors.New("decode: message is not a multiple of four bytes") 144 } 145 146 numTags := uint64(binary.LittleEndian.Uint32(bytes)) 147 148 if numTags == 0 { 149 return make(map[uint32][]byte), nil 150 } 151 152 if uint64(len(bytes)) < 4*((numTags-1)+numTags) { 153 return nil, errors.New("decode: message too short to be valid") 154 } 155 156 offsets := bytes[4:] 157 tags := bytes[4*(1+numTags-1):] 158 payloads := bytes[4*(1+(numTags-1)+numTags):] 159 160 if len(payloads) > math.MaxInt32 { 161 return nil, errors.New("decode: message too large") 162 } 163 payloadLength := uint32(len(payloads)) 164 165 currentOffset := uint32(0) 166 var lastTag uint32 167 ret := make(map[uint32][]byte) 168 169 for i := uint64(0); i < numTags; i++ { 170 tag := binary.LittleEndian.Uint32(tags) 171 tags = tags[4:] 172 173 if i > 0 && lastTag >= tag { 174 return nil, errors.New("decode: tags out of order") 175 } 176 177 var nextOffset uint32 178 if i < numTags-1 { 179 nextOffset = binary.LittleEndian.Uint32(offsets) 180 offsets = offsets[4:] 181 } else { 182 nextOffset = payloadLength 183 } 184 185 if nextOffset%4 != 0 { 186 return nil, errors.New("decode: payload length is not a multiple of four bytes") 187 } 188 189 if nextOffset < currentOffset { 190 return nil, errors.New("decode: offsets out of order") 191 } 192 193 length := nextOffset - currentOffset 194 if uint32(len(payloads)) < length { 195 return nil, errors.New("decode: message truncated") 196 } 197 198 payload := payloads[:length] 199 payloads = payloads[length:] 200 ret[tag] = payload 201 currentOffset = nextOffset 202 } 203 204 return ret, nil 205 } 206 207 // messageOverhead returns the number of bytes needed for Encode to encode the 208 // given number of tags. 209 func messageOverhead(numTags int) int { 210 return 4 * 2 * numTags 211 } 212 213 // CalculateChainNonce calculates the nonce to be used in the next request in a 214 // chain given a reply and a blinding factor. 215 func CalculateChainNonce(prevReply, blind []byte) (nonce [NonceSize]byte) { 216 h := sha512.New() 217 h.Write(prevReply) 218 prevReplyHash := h.Sum(nil) 219 220 h.Reset() 221 h.Write(prevReplyHash) 222 h.Write(blind) 223 h.Sum(nonce[:0]) 224 225 return nonce 226 } 227 228 // CreateRequest creates a Roughtime request given an entropy source and the 229 // contents of a previous reply for chaining. If this request is the first of a 230 // chain, prevReply can be empty. It returns the nonce (needed to verify the 231 // reply), the blind (needed to prove correct chaining to an external party) 232 // and the request itself. 233 func CreateRequest(rand io.Reader, prevReply []byte) (nonce, blind [NonceSize]byte, request []byte, err error) { 234 if _, err := io.ReadFull(rand, blind[:]); err != nil { 235 return nonce, blind, nil, err 236 } 237 238 nonce = CalculateChainNonce(prevReply, blind[:]) 239 240 padding := make([]byte, MinRequestSize-messageOverhead(2)-len(nonce)) 241 msg, err := Encode(map[uint32][]byte{ 242 tagNONC: nonce[:], 243 tagPAD: padding, 244 }) 245 if err != nil { 246 return nonce, blind, nil, err 247 } 248 249 return nonce, blind, msg, nil 250 } 251 252 // tree represents a Merkle tree of nonces. Each element of values is a layer 253 // in the tree, with the widest layer first. 254 type tree struct { 255 values [][][NonceSize]byte 256 } 257 258 var ( 259 hashLeafTweak = []byte{0} 260 hashNodeTweak = []byte{1} 261 ) 262 263 // hashLeaf hashes an nonce to form the leaf of the Merkle tree. 264 func hashLeaf(out *[sha512.Size]byte, in []byte) { 265 h := sha512.New() 266 h.Write(hashLeafTweak) 267 h.Write(in) 268 h.Sum(out[:0]) 269 } 270 271 // hashNode hashes two child elements of the Merkle tree to produce an interior 272 // node. 273 func hashNode(out *[sha512.Size]byte, left, right []byte) { 274 h := sha512.New() 275 h.Write(hashNodeTweak) 276 h.Write(left) 277 h.Write(right) 278 h.Sum(out[:0]) 279 } 280 281 // newTree creates a Merkle tree given one or more nonces. 282 func newTree(nonces [][]byte) *tree { 283 if len(nonces) == 0 { 284 panic("newTree: passed empty slice") 285 } 286 287 levels := 1 288 width := len(nonces) 289 for width > 1 { 290 width = (width + 1) / 2 291 levels++ 292 } 293 294 ret := &tree{ 295 values: make([][][NonceSize]byte, 0, levels), 296 } 297 298 leaves := make([][NonceSize]byte, ((len(nonces)+1)/2)*2) 299 for i, nonce := range nonces { 300 var leaf [NonceSize]byte 301 hashLeaf(&leaf, nonce) 302 leaves[i] = leaf 303 } 304 ret.values = append(ret.values, leaves) 305 306 for i := 1; i < levels; i++ { 307 lastLevel := ret.values[i-1] 308 width := len(lastLevel) / 2 309 if width%2 == 1 { 310 width++ 311 } 312 level := make([][NonceSize]byte, width) 313 for j := 0; j < len(lastLevel)/2; j++ { 314 hashNode(&level[j], lastLevel[j*2][:], lastLevel[j*2+1][:]) 315 } 316 ret.values = append(ret.values, level) 317 } 318 319 return ret 320 } 321 322 // Root returns the root value of t. 323 func (t *tree) Root() *[NonceSize]byte { 324 return &t.values[len(t.values)-1][0] 325 } 326 327 // Levels returns the number of levels in t. 328 func (t *tree) Levels() int { 329 return len(t.values) 330 } 331 332 // Path returns elements from t needed to prove, given the root, that the leaf 333 // at the given index is in the tree. 334 func (t *tree) Path(index int) (path [][]byte) { 335 path = make([][]byte, 0, len(t.values)) 336 337 for level := 0; level < len(t.values)-1; level++ { 338 if index%2 == 1 { 339 path = append(path, t.values[level][index-1][:]) 340 } else { 341 path = append(path, t.values[level][index+1][:]) 342 } 343 344 index /= 2 345 } 346 347 return path 348 } 349 350 // CreateReplies signs, using privateKey, a batch of nonces along with the 351 // given time and radius in microseconds. It returns one reply for each nonce 352 // using that signature and includes cert in each. 353 func CreateReplies(nonces [][]byte, midpoint uint64, radius uint32, cert []byte, privateKey []byte) ([][]byte, error) { 354 if len(nonces) == 0 { 355 return nil, nil 356 } 357 358 tree := newTree(nonces) 359 360 var midpointBytes [8]byte 361 binary.LittleEndian.PutUint64(midpointBytes[:], midpoint) 362 var radiusBytes [4]byte 363 binary.LittleEndian.PutUint32(radiusBytes[:], radius) 364 365 signedReply := map[uint32][]byte{ 366 tagMIDP: midpointBytes[:], 367 tagRADI: radiusBytes[:], 368 tagROOT: tree.Root()[:], 369 } 370 signedReplyBytes, err := Encode(signedReply) 371 if err != nil { 372 return nil, err 373 } 374 375 toBeSigned := signedResponseContext + string(signedReplyBytes) 376 sig := ed25519.Sign(privateKey, []byte(toBeSigned)) 377 378 reply := map[uint32][]byte{ 379 tagSREP: signedReplyBytes, 380 tagSIG: sig, 381 tagCERT: cert, 382 } 383 384 replies := make([][]byte, 0, len(nonces)) 385 386 for i := range nonces { 387 var indexBytes [4]byte 388 binary.LittleEndian.PutUint32(indexBytes[:], uint32(i)) 389 reply[tagINDX] = indexBytes[:] 390 391 path := tree.Path(i) 392 pathBytes := make([]byte, 0, NonceSize*len(path)) 393 for _, pathStep := range path { 394 pathBytes = append(pathBytes, pathStep...) 395 } 396 reply[tagPATH] = pathBytes 397 398 replyBytes, err := Encode(reply) 399 if err != nil { 400 return nil, err 401 } 402 403 replies = append(replies, replyBytes) 404 } 405 406 return replies, nil 407 } 408 409 // CreateCertificate returns a signed certificate, using rootPrivateKey, 410 // delegating authority for the given timestamp to publicKey. 411 func CreateCertificate(minTime, maxTime uint64, publicKey, rootPrivateKey []byte) (certBytes []byte, err error) { 412 if maxTime < minTime { 413 return nil, errors.New("protocol: maxTime < minTime") 414 } 415 416 var minTimeBytes, maxTimeBytes [8]byte 417 binary.LittleEndian.PutUint64(minTimeBytes[:], minTime) 418 binary.LittleEndian.PutUint64(maxTimeBytes[:], maxTime) 419 420 signed := map[uint32][]byte{ 421 tagPUBK: publicKey, 422 tagMINT: minTimeBytes[:], 423 tagMAXT: maxTimeBytes[:], 424 } 425 426 signedBytes, err := Encode(signed) 427 if err != nil { 428 return nil, err 429 } 430 431 toBeSigned := certificateContext + string(signedBytes) 432 sig := ed25519.Sign(rootPrivateKey, []byte(toBeSigned)) 433 434 cert := map[uint32][]byte{ 435 tagSIG: sig, 436 tagDELE: signedBytes, 437 } 438 439 return Encode(cert) 440 } 441 442 func getValue(msg map[uint32][]byte, tag uint32, name string) (value []byte, err error) { 443 value, ok := msg[tag] 444 if !ok { 445 return nil, errors.New("protocol: missing " + name) 446 } 447 return value, nil 448 } 449 450 func getFixedLength(msg map[uint32][]byte, tag uint32, name string, length int) (value []byte, err error) { 451 value, err = getValue(msg, tag, name) 452 if err != nil { 453 return nil, err 454 } 455 if len(value) != length { 456 return nil, errors.New("protocol: incorrect length for " + name) 457 } 458 return value, nil 459 } 460 461 func getUint32(msg map[uint32][]byte, tag uint32, name string) (result uint32, err error) { 462 valueBytes, err := getFixedLength(msg, tag, name, 4) 463 if err != nil { 464 return 0, err 465 } 466 return binary.LittleEndian.Uint32(valueBytes), nil 467 } 468 469 func getUint64(msg map[uint32][]byte, tag uint32, name string) (result uint64, err error) { 470 valueBytes, err := getFixedLength(msg, tag, name, 8) 471 if err != nil { 472 return 0, err 473 } 474 return binary.LittleEndian.Uint64(valueBytes), nil 475 } 476 477 func getSubmessage(msg map[uint32][]byte, tag uint32, name string) (result map[uint32][]byte, err error) { 478 valueBytes, err := getValue(msg, tag, name) 479 if err != nil { 480 return nil, err 481 } 482 483 result, err = Decode(valueBytes) 484 if err != nil { 485 return nil, errors.New("protocol: failed to parse " + name + ": " + err.Error()) 486 } 487 488 return result, nil 489 } 490 491 // VerifyReply parses the Roughtime reply in replyBytes, authenticates it using 492 // publicKey and verifies that nonce is included in it. It returns the included 493 // timestamp and radius. 494 func VerifyReply(replyBytes, publicKey []byte, nonce [NonceSize]byte) (time uint64, radius uint32, err error) { 495 reply, err := Decode(replyBytes) 496 if err != nil { 497 return 0, 0, errors.New("protocol: failed to parse top-level reply: " + err.Error()) 498 } 499 500 cert, err := getSubmessage(reply, tagCERT, "certificate") 501 if err != nil { 502 return 0, 0, err 503 } 504 505 signatureBytes, err := getFixedLength(cert, tagSIG, "signature", ed25519.SignatureSize) 506 if err != nil { 507 return 0, 0, err 508 } 509 510 delegationBytes, err := getValue(cert, tagDELE, "delegation") 511 if err != nil { 512 return 0, 0, err 513 } 514 515 if !ed25519.Verify(publicKey, []byte(certificateContext+string(delegationBytes)), signatureBytes) { 516 return 0, 0, errors.New("protocol: invalid delegation signature") 517 } 518 519 delegation, err := Decode(delegationBytes) 520 if err != nil { 521 return 0, 0, errors.New("protocol: failed to parse delegation: " + err.Error()) 522 } 523 524 minTime, err := getUint64(delegation, tagMINT, "minimum time") 525 if err != nil { 526 return 0, 0, err 527 } 528 529 maxTime, err := getUint64(delegation, tagMAXT, "maximum time") 530 if err != nil { 531 return 0, 0, err 532 } 533 534 delegatedPublicKey, err := getFixedLength(delegation, tagPUBK, "public key", ed25519.PublicKeySize) 535 if err != nil { 536 return 0, 0, err 537 } 538 539 responseSigBytes, err := getFixedLength(reply, tagSIG, "signature", ed25519.SignatureSize) 540 if err != nil { 541 return 0, 0, err 542 } 543 544 signedResponseBytes, ok := reply[tagSREP] 545 if !ok { 546 return 0, 0, errors.New("protocol: response is missing signed portion") 547 } 548 549 if !ed25519.Verify(delegatedPublicKey, []byte(signedResponseContext+string(signedResponseBytes)), responseSigBytes) { 550 return 0, 0, errors.New("protocol: invalid response signature") 551 } 552 553 signedResponse, err := Decode(signedResponseBytes) 554 if err != nil { 555 return 0, 0, errors.New("protocol: failed to parse signed response: " + err.Error()) 556 } 557 558 root, err := getFixedLength(signedResponse, tagROOT, "root", sha512.Size) 559 if err != nil { 560 return 0, 0, err 561 } 562 563 midpoint, err := getUint64(signedResponse, tagMIDP, "midpoint") 564 if err != nil { 565 return 0, 0, err 566 } 567 568 radius, err = getUint32(signedResponse, tagRADI, "radius") 569 if err != nil { 570 return 0, 0, err 571 } 572 573 if maxTime < minTime { 574 return 0, 0, errors.New("protocol: invalid delegation range") 575 } 576 577 if midpoint < minTime || maxTime < midpoint { 578 return 0, 0, errors.New("protocol: timestamp out of range for delegation") 579 } 580 581 index, err := getUint32(reply, tagINDX, "index") 582 if err != nil { 583 return 0, 0, err 584 } 585 586 path, err := getValue(reply, tagPATH, "path") 587 if err != nil { 588 return 0, 0, err 589 } 590 if len(path)%sha512.Size != 0 { 591 return 0, 0, errors.New("protocol: path is not a multiple of the hash size") 592 } 593 594 var hash [sha512.Size]byte 595 hashLeaf(&hash, nonce[:]) 596 597 for len(path) > 0 { 598 pathElementIsRight := index&1 == 0 599 if pathElementIsRight { 600 hashNode(&hash, hash[:], path[:sha512.Size]) 601 } else { 602 hashNode(&hash, path[:sha512.Size], hash[:]) 603 } 604 605 index >>= 1 606 path = path[sha512.Size:] 607 } 608 609 if !bytes.Equal(hash[:], root) { 610 return 0, 0, errors.New("protocol: calculated tree root doesn't match signed root") 611 } 612 613 return midpoint, radius, nil 614 }