bmp-string.go raw

   1  // Copyright 2015 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package pkcs12
   6  
   7  import (
   8  	"errors"
   9  	"unicode/utf16"
  10  )
  11  
  12  // bmpString returns s encoded in UCS-2 with a zero terminator.
  13  func bmpString(s string) ([]byte, error) {
  14  	// References:
  15  	// https://tools.ietf.org/html/rfc7292#appendix-B.1
  16  	// https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
  17  	//  - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
  18  	//	  EncodeRune returns 0xfffd if the rune does not need special encoding
  19  	//  - the above RFC provides the info that BMPStrings are NULL terminated.
  20  
  21  	ret := make([]byte, 0, 2*len(s)+2)
  22  
  23  	for _, r := range s {
  24  		if t, _ := utf16.EncodeRune(r); t != 0xfffd {
  25  			return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
  26  		}
  27  		ret = append(ret, byte(r/256), byte(r%256))
  28  	}
  29  
  30  	return append(ret, 0, 0), nil
  31  }
  32  
  33  func decodeBMPString(bmpString []byte) (string, error) {
  34  	if len(bmpString)%2 != 0 {
  35  		return "", errors.New("pkcs12: odd-length BMP string")
  36  	}
  37  
  38  	// strip terminator if present
  39  	if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
  40  		bmpString = bmpString[:l-2]
  41  	}
  42  
  43  	s := make([]uint16, 0, len(bmpString)/2)
  44  	for len(bmpString) > 0 {
  45  		s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
  46  		bmpString = bmpString[2:]
  47  	}
  48  
  49  	return string(utf16.Decode(s)), nil
  50  }
  51